I'm trying to send a frame Ethernet in a Linux system by the C function sendto()
. The frame does not contain any IP level information because the IP protocol is not used in my application.
The sendto() documentation provides the following information:
Signature of the function sendto()
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
The buffer to transmit
For send() and sendto(), the message is found in buf and has length len.
The destination address
If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) socket, the arguments dest_addr and addrlen are ignored (and the error EISCONN may be returned when they are not NULL and 0), and the error ENOTCONN is returned when the socket was not actually connected. Otherwise, the address of the target is given by dest_addr with addrlen specifying its size.
In my case the socket is created by the following instruction (see here for manual Linux manual page dedicated to socket()
function):
int sck_dgram = socket(AF_PACKET, SOCK_DGRAM, 0);
and so it is NOT a connection-mode socket. To set the destination address I use the following instructions:
struct sockaddr_ll dest_addr = {0};
dest_addr.sll_family = AF_PACKET;
dest_addr.sll_ifindex = ifindex;
dest_addr.sll_halen = ETHER_ADDR_LEN;
memcpy(dest_addr.sll_addr, mac_dest, ETHER_ADDR_LEN);
where mac_dest
is an array that contains the MAC address destination and ifindex
is the index of the ethernet interface used for the send.
My sendto() instruction
In conclusion, to send the buf[BUFFSIZE]
array of data I use the following sendto()
instruction:
sendto(sck_dgram, buf, BUFFSIZE, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr))
With the previous instruction I can set only the target MAC address (bytes from 0 to 5 of the frame) by dest_addr
but not the source MAC address of the frame (the bytes from 6 to 11 of the frame). The source MAC address is automatically set equal to MAC address of the Ethernet Interface used for the send.
My question
Is it possible send a frame Ethernet with a source MAC address different from the MAC address of the Ethernet Interface used for the send?
EDIT: The solution of the problem is the modification of the instruction which creates the socket by the substitution of SOCK_DGRAM
with SOCK_RAW
. The right instruction is:
int sck_raw = socket(AF_PACKET, SOCK_RAW, 0);
According to the previous instruction I have to modify the sendto()
instruction so that the buf[]
include 14 octets with the destination mac address, source mac address and ether type. This data must be place in the first 14 bytes of buf[]
. So I have to increase the size of buf
as followed:
char buf[BUFFSIZE+14];
// set buf[0] .. buf[5] with mac dest
// set buf[6] .. buf[11] with mac source
// set buf[12] and buf[13] with ether type (set to 0x0200 and this is the data lenght)
// sendto() becomes:
sendto(sck_raw, buf, BUFFSIZE+14, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr))
This Wikipedia link explains the ethernet frame structure.