I am using boost::asio::generic::raw_protocol::socket
to open a socket of family PF_PACKET
and type SOCK_DGRAM
.
In my header file:
class MyClass
{
public:
MyClass(/*parameters*/);
typedef boost::asio::generic::raw_protocol raw_protocol_t;
typedef boost::asio::generic::basic_endpoint<raw_protocol_t> raw_endpoint_t;
void SetDestinationEndPoint(int ifIndex, int protocol, const uint8_t *destinationMacAddress);
private:
boost::shared_ptr<raw_protocol_t::socket> m_socketPtr;
raw_endpoint_t *m_pDestinationEndpoint;
};
In the .cpp file:
MyClass::MyClass(/*parameters*/):
m_socketPtr(new raw_protocol_t::socket(IOWorker.get_service()) //in my class constructor
{
//constructor body
m_socketPtr->open(raw_protocol_t(PF_PACKET, SOCK_DGRAM));
sockaddr_ll sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sll_family = AF_PACKET;
sockaddr.sll_protocol = htons(protocol);
sockaddr.sll_ifindex = ifIndex;
m_socketPtr->bind(raw_endpoint_t(&sockaddr, sizeof(sockaddr)));
}
//then User sets destination endpoint
void MyClass::SetDestinationEndPoint(int ifIndex, int protocol, const uint8_t *destinationMacAddress)
{
struct sockaddr_ll ll;
memset(&ll, 0, sizeof(ll));
ll.sll_family = AF_PACKET;
ll.sll_ifindex = ifIndex;
ll.sll_protocol = htons(protocol);
ll.sll_halen = ETH_ALEN;
memcpy(ll.sll_addr, destinationMacAddress, ETH_ALEN);
m_pDestinationEndpoint = new raw_endpoint_t(&ll, sizeof(ll), protocol);
}
Finally, a call to async_send_to
is made to initiate sending of the payload:
m_socketPtr->async_send_to(boost::asio::buffer(bufferPtr->GetBuffer().get(), bufferPtr->GetBufferSize()),
*m_pDestinationEndpoint,
boost::bind(/*params*/));
The buffer contains only the Ethernet payload and does not include the Ethernet header. As per my understanding, everything required to construct the Ethernet header is present in *m_pDestinationEndpoint
(Set using the call to SetDestinationEndPoint()
). However, I notice that just the payload is getting sent without the Ethernet header. What am I missing here? Secondly, is it necessary to use a separate destination endpoint, or can I use m_socketPtr->local_endpoint()
in the call to async_send_to
(of course setting the destination MAC address in the constructor itself prior to calling bind
)?
Attaching strace
to the process provided a hint:
strace -e trace=network -p `pidof <process name>`
I expected to find
socket(PF_PACKET, SOCK_DGRAM, 1)
But instead found
socket(PF_PACKET, SOCK_RAW, 1)
which led me to believe the 2nd parameter to the open
call of socket
class does not specify socket type but protocol family
So I changed the protocol class from raw_protocol
to datagram_protocol
(and similar changes to endpoint classes) and it worked!
class MyClass
{
public:
MyClass(/*parameters*/);
typedef boost::asio::generic::datagram_protocol datagram_protocol_t;
typedef boost::asio::generic::basic_endpoint<datagram_protocol_t> datagram_endpoint_t;
void SetDestinationEndPoint(int ifIndex, int protocol, const uint8_t *destinationMacAddress);
private:
boost::shared_ptr<datagram_protocol_t::socket> m_socketPtr;
datagram_endpoint_t *m_pDestinationEndpoint;
};