How to send data over a raw ethernet socket using sendto without using sockaddr_ll?
c, ose, sockets
Solution
Sorry about the previous vague answer. Here is my full answer. Hope its helpful.
To answer your question: Yes, you can send using just the MAC Address.
Declare the socket like this:
int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)
On error, sockfd which is the socket file descriptor will return -1.
The struct for the Ethernet frame can be constructed like this:
struct ethernet_msg{
char destination_mac[6];
char source_mac[6];
char transport_protocol[2];
char data1[6];
char data2[6];
char data3[8];
char data4[8];
char data5[8];
char data6[2];
char data7[2];
char data8[6];
char data9[4];
char data10[6];
};
struct ethernet_msg my_msg = {
{0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00},//destination_mac
{0x08, 0x00, 0x27, 0x90, 0x5f, 0xae},//source_mac
{0x22, 0xf0},//transport_protocol
{0xfc, 0x06, 0x00, 0x2c, 0x00, 0x00},//data1
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//data2
{0x08, 0x00, 0x27, 0xff, 0xfe, 0x90, 0x5f, 0xae},//data3
{0xd8, 0x80, 0x39, 0xff, 0xfe, 0xd0, 0xac, 0xb5},//data4
{0xd8, 0x80, 0x39, 0xff, 0xfe, 0xd0, 0x9b, 0xc8},//data5
{0x00, 0x00},//data6
{0x00, 0x00},//data7
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//data8
{0x00, 0x00, 0x00, 0x5f},//data9
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}//data10
};
Note how I put char arrays of different lengths inside the frame. You can set this according to your needs. To get the MAC address of the interface to send on:
void get_interface_MAC(char interface_name[IFNAMSIZ], int sockfd)
{
struct ifreq if_mac;
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, interface_name, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
}
Then to get the index of the network device:
/* Get the index of the interface to send on */
int get_interface_index(char interface_name[IFNAMSIZ], int sockfd)
{
struct ifreq if_idx;
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, interface_name, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)
perror("SIOCGIFINDEX");
return if_idx.ifr_ifindex;
}
socket_address.sll_ifindex = get_interface_index(interface_name, sockfd);
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
memcpy(socket_address.sll_addr, avdecc_msg.destination_mac, ETH_ALEN);
And then to finally send this over a socket:
/* Send packet */
if (sendto(sockfd, &avdecc_msg, sizeof(avdecc_msg), 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
Hope that helps. I used this link and refined the code to get to this. It worked for me.
Problem
I am working on a project where we use Enea OSE which is a real time embedded operating system. I guess many of you are not familiar with this OS but I think you could answer my question anyway. I want to send a raw ethernet frame between 2 cards using interface "eth1" which are directly connected to oneanother by an ethernet cable (no switch or anything). The "eth1" interface is not assigned any ip-address. I can simply declare a socket using ``` int s = socket(AF_INET, RAW_SOCKET, ...) ``` I can then bind the socket to the appropriate device interface using: ``` setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, "eth1", 4); ``` What my plan was to do, in order to send data from one card to the other, was to manually fill in a ethernet buffer array with the source and destination MAC adresses. Then send the data using sendto(....) However the sendto routine also requires a sockaddr struct with information: ``` sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); ``` In the examples I have found on the internet uses sockaddr_in when the ip adress is known and sockaddr_ll for raw frames. However OSE does not provide the sockaddr_ll struct. However it provides the sockaddr which I dont know if I can use for raw ethernet frames? ``` struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol address }; ``` I also tried to use NULL, for the sockaddr field when calling sendto(), the send fails. This brings me to my questions(s). Can I use the simple sockaddr struct to fill in the destination MAC-adress without using any IP? How would that look? (I have not seeen any code showing this). Why do we even have to provide a sockaddr struct? Doesn't the ethernet data buffer already contain this information? Finally, is what I am trying to accomplish even possible without assigning ip-addresses for the network devices? I am aware of what I am trying to do seems peculiar but there is a reason for it :) I would be really glad if you would show me how to accomplish this without having to use the sockaddr_ll struct.