3

I am working with RAW sockets on Linux/Debian and I have a problem when I use write() instead of sendto():

struct sockaddr_ll socket_address;
/* Index of the network device */
socket_address.sll_ifindex = if_idx.ifr_ifindex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = 0x00;
socket_address.sll_addr[1] = 0x11;
socket_address.sll_addr[2] = 0x22;
socket_address.sll_addr[3] = 0x33;
socket_address.sll_addr[4] = 0x44;
socket_address.sll_addr[5] = 0x55;

/* Send packet */
int b_written = 0;

if ( ( b_written = write(sockfd, sendbuf, tx_len,
                                   (struct sockaddr*)&socket_address,
                                    sizeof(struct sockaddr_ll))) < 0 )
/*
if ( ( b_written = sendto(sockfd, sendbuf, tx_len, 0,
                                   (struct sockaddr*)&socket_address,
                    sizeof(struct sockaddr_ll))) < 0 )
*/
{
    perror("Could not write socket...");
    fprintf(stderr, "ERRNO = %d\n", errno);
    exit(-1);
}
printf("Packet sent!, Bytes written = %d\n", b_written);

If I use write instead of sendto, I get the following perror:

No such device or address" (errno=6, which is defined as EXNIO).

Using sendto, I have no problem and packet is shown in tcpdump -nettti eth0 '(ether dst host 00:11:22:33:44:55)'.

In accordance with man sendto, sendto is equivalent to a write without specifying any flags. Since the flags field that I use for sendto is '0', I guess that both system calls are equivalent.

What might I be doing wrong? Is it correct that both calls are equivalent?

4
  • write() can't have 5 parameters. Commented Jul 3, 2013 at 11:01
  • As for the contents of that manpage, it seems that the only differences between sendto() and sendmsg() are how to pass the arguments to those functions. Why should it be more appropriate to use "sendmsg()" than "sendto()" for a link layer level RAW socket? Commented Jul 3, 2013 at 11:37
  • Is this the original code. Did you mean write or send. What nouney said is right, i think. If it is send, then you cannot use it for connectionless service eg: SOCK_RAW Commented Jul 3, 2013 at 11:39
  • As you can see in the code, my issue is between the usage of "write" and "sendto". I started using "write" since the socket is connectionless; however, after getting the EXNIO error, I started using "sendto()" since I think that it does not require a connection to be established before sending data. In my case, the latter ("sendto()") is working fine and I can even see the packet with tcpdump. Commented Jul 3, 2013 at 11:46

3 Answers 3

3

You have to bind() (see manual) the address to your socket, then use write() correctly (That means, with only 3 parameters).

/* Send packet */
int b_written = 0;

if (bind(sockfd, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) == -1)
{
    perror("bind");
    exit(-1);
}
if ( ( b_written = write(sockfd, sendbuf, tx_len)) < 0 )
{
    perror("Could not write socket...");
    fprintf(stderr, "ERRNO = %d\n", errno);
    exit(-1);
}
printf("Packet sent!, Bytes written = %d\n", b_written);
Sign up to request clarification or add additional context in comments.

1 Comment

Yes, this solves the problem. Thank you @nouney! Please find the full solution in my answer below since it is important to fill up certain fields of the sockaddr_ll structure.
2

The sendto() call may be used only when the socket is in a connected state (so that the intended recipient is known). Following is the prototype of write function and it has 3 parameters not 5 like send() function.

write(int fd, const void *buf, size_t count);

11 Comments

Even with 3 arguments, I get the same errno #6 (EXNIO: "No such device or address"). The call to write is as follows: write(sockfd, sendbuf, tx_len).
A newer question that comes to my mind is: if in accordance with "write"'s manpage, this function has 3 arguments, why can I compile and execute my code passing 5 arguments to "write"? Does it support multiple arguments and ignores those that it does not need? Shouldn't GCC warn me (at least) about this issue?
@Ricardo No it don't support multiple arguments. What's your compiler option ? Did you compile with -Wall ?
@Ricardo if you include unistd.h, gcc will tell you that you don't use it correctly.
@nouney , OK, thanks for the explanation... I would never have thought that GCC would trust somebody like me... :)
|
0

This message results from I/O to a special file's subdevice that either does not exist or that exists beyond the limit of the device. So check, Do you have permission or access to write where you want to perform write operation. Also change write parameters as it can have only three parameters.

from man page

int write(fd, buf, nbyte)

I hope this solve the issue.

4 Comments

why would he get an error for write but not sendto if it's a permission error?
Right now, I am executing that application as <root>, since I also need privileges for opening the socket; so I guess that it is not a permissions issue.
@Ricardo... I said that because you are getting errno=6, which means device not present. if you have that device physically(as I assumed), then there is only one problem. So check the device file. The permissions must read 666 (crw-rw-rw-).
@Krishna he said he sees the data in tcpdump, so the device clearly exists and he has permissions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.