I am using Enea OSE and want to send a raw ethernet frame without any IP by opening a raw socket. Note that OSE uses the NetBSD stack which seems to be a little different from the Linux-stack.
The problem is that I havent found any good examples for doing this in OSE, however the same methods exists basically for opening a socket and sending (sendto) etc. However the *sockaddr_ll* struct which is used in Linux for sending raw ethernet frames does not exist in OSE. But I found another struct, *sockaddr_dl* which basically seems to have the same fields:
struct sockaddr_dl
{
uint8_t sdl_len;
sa_family_t sdl_family; //AF_LINK
uint16_t sdl_index;
uint8_t sdl_type;
uint8_t sdl_nlen;
uint8_t sdl_alen;
uint8_t sdl_slen;
char sdl_data[12];
}
I have found one article which discusses the differences between the Linux and the NetBSD stack, http://sock-raw.org/papers/sock_raw
I can open the socket without any error but the sendto() function fails with error value 22, Invalid Argument. What might the problem be? All threads I have read with this error ocurring people have not been careful when using sizeof at a pointer, but that is not what this is about I think. Ofcourse I am not certain that the sockaddr_dl struct is suited for raw sockets and perhaps it might be some problem there? Also perhaps the ethernet buffer is not filled in correctly? Also note that the socket used in Linux is opened the following way for this purpose:
int sock = socket(AF_PACKET, SOCK_RAW, ...)
but this is not possible since the AF_PACKET is not included in OSE. From the article above it seems that a raw socket should be opened as shown in my code below.
int sockfd;
char sendbuf[FRAME_SIZE];
int tx_len = FRAME_SIZE;
/* Open RAW socket to send on */
if ((sockfd = socket(AF_INET, SOCK_RAW, 0)) == -1) {
printf("Error when opening socket: %s\n", strerror(errno));
}
/*Fill sockaddr_dl struct (Link - Layer)*/
unsigned char src_mac[6] = {0x00, 0x80, 0x81, 0x82, 0x83, 0x84};
unsigned char dst_mac[6] = {0x00, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e};
struct sockaddr_dl sock_test;
memset(&sock_test, 0, sizeof (struct sockaddr_dl));
sock_test.sdl_family = AF_LINK;
sock_test.sdl_len = sizeof (struct sockaddr_dl);
sock_test.sdl_index = 0;
sock_test.sdl_type = IFT_ETHER;
sock_test.sdl_alen = ETH_LEN; //ETHER_ADDR_LEN = 6;
sock_test.sdl_data[0] = dst_mac[0];
sock_test.sdl_data[1] = dst_mac[1];
sock_test.sdl_data[2] = dst_mac[2];
sock_test.sdl_data[3] = dst_mac[3];
sock_test.sdl_data[4] = dst_mac[4];
sock_test.sdl_data[5] = dst_mac[5];
/*Fill in ethernet frame*/
unsigned char ether_type[2] = {0x08, 0x00};
memset((void*)sendbuf, 0, FRAME_SIZE); //Clear buffer
memcpy((void*)sendbuf, (void*)dst_mac, ETH_LEN);
memcpy((void*) (sendbuf+ETH_LEN), (void*)src_mac, ETH_LEN);
memcpy((void*) (sendbuf+2*ETH_LEN), (void*)ether_type, 2);
int status = sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&sock_test, (socklen_t)sizeof(sock_test));
if(status < 0){
printf("Error: %s :::: with value %d\n", strerror(errno), errno);
}
else
printf("SENT DONE!!! \n");
Any suggestions are mostly welcome!
memcpy((void*)sendbuf, 0, FRAME_SIZE); //Clear buffer
, should be amemset
asmemcpy
will treat the0
as aconst void*
for its source which, in this case, you are copying the memory of a temp stack variable (when your intention is to simply 0 a buffer). – txtechhelpmemcpy((void*) (sendbuf+2*ETH_LEN), (void*)ether_type, 2);
the(sendbuf+2*ETH_LEN)
part ... keep operator precedence in mind on this too as it's actually being evaluated to(sendbuf+(2*ETH_LEN))
since multiplication has higher precedence than addition – txtechhelpAF_PACKET
is not available? Have you tried thePF_PACKET
variant? – txtechhelp