Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ioctl, ARP, help..

822 views
Skip to first unread message

frederic pont

unread,
Jun 8, 1999, 3:00:00 AM6/8/99
to
Hi all,

I want to get an entry from the ARP cache on Linux 2.2.4 using ioctl().
I always get this error message :
ioctl: Operation not supported by device

I run the program as root. Here is the code, I don't know what's wrong.
Any idea ?

---------------------------------
#include <net/if_arp.h>
#include <sys/ioctl.h>
#include <netinet/in.h>

void main(void) {

int sockfd;
struct arpreq myarp;
struct sockaddr_in *sin;
struct in_addr inaddr;

sockfd = socket(AF_INET,SOCK_DGRAM, 0);

inaddr.s_addr = inet_addr("10.10.10.1");
sin = (struct sockaddr_in *) &myarp.arp_pa;
bzero(sin, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;

memcpy(&sin->sin_addr, &inaddr, sizeof(struct in_addr));

if((ioctl(sockfd, SIOCGARP, &myarp)) != 0) {
perror("ioctl");
exit(0);
}

}
-----------------------------------------

Thanks
Fred


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.

Kaz Kylheku

unread,
Jun 8, 1999, 3:00:00 AM6/8/99
to
On Tue, 08 Jun 1999 17:05:06 GMT, frederic pont <freder...@epfl.ch> wrote:
>Hi all,
>
>I want to get an entry from the ARP cache on Linux 2.2.4 using ioctl().
>I always get this error message :
>ioctl: Operation not supported by device
>
>I run the program as root. Here is the code, I don't know what's wrong.
>Any idea ?
>
>---------------------------------
>#include <net/if_arp.h>
>#include <sys/ioctl.h>
>#include <netinet/in.h>
>
>void main(void) {
^^^^ ahem!

> int sockfd;
> struct arpreq myarp;
> struct sockaddr_in *sin;
> struct in_addr inaddr;
>
> sockfd = socket(AF_INET,SOCK_DGRAM, 0);
>
> inaddr.s_addr = inet_addr("10.10.10.1");

You are missing the declaration for this function. It is declared in
<arpa/inet.h>. The compiler-generated implicit declaration will not do because
the return value is not int! Use the -Wall option of gcc.

Note that this method of initializing a struct in_addr is obsolete. It's better
to do

if (inet_aton(some_addr_string, &inaddr) == 0) {
/* address string is bad */
}

This method can handle the address 255.255.255.255 without interpreting it as
error, and keeps the representation of struct in_addr opaque.

> sin = (struct sockaddr_in *) &myarp.arp_pa;
> bzero(sin, sizeof(struct sockaddr_in));

Use ANSI C memset(). bzero is an obsolete BSD-ism.

> sin->sin_family = AF_INET;
>
> memcpy(&sin->sin_addr, &inaddr, sizeof(struct in_addr));

ANSI C supports structure assignment. You can assign one struct in_addr
to another:

sin->sin_addr = inaddr;

You could write all of this more simply as:

struct sockaddr_in sin = { 0 };
struct arpreq myarp = { 0 };

sin.sin_family = AF_INET;
inet_aton("10.10.10.1", &sin.sin_addr);

memcpy(&myarp.arp_pa, &sin, sizeof myarp.arp_pa);
strcpy(myarp.arp_dev, "eth0");


> if((ioctl(sockfd, SIOCGARP, &myarp)) != 0) {
> perror("ioctl");
> exit(0);
> }

How about initializing the rest of that arpreq structure? There is, for
example, a device field (arp_dev) that you left uninitialized.

You might want to add an initializer to the declaration of myarp, like

struct arpreq myarp = { 0 }; /* zero out all fields */

This way, any char[] fields are empty strings, ints are zeros,
pointers are NULL, doubles are 0.0 etc.

The arp_dev field is not optional. If it is an empty string, the
SIOCGARP ioctl() will immediately return -ENODEV. Here is the 2.2.9 code
that does it:

if (r.arp_dev[0]) {
err = -ENODEV;
if ((dev = dev_get(r.arp_dev)) == NULL)
goto out;

/* Mmmm... It is wrong... ARPHRD_NETROM==0 */
if (!r.arp_ha.sa_family)
r.arp_ha.sa_family = dev->type;
err = -EINVAL;
if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type)
goto out;
} else if (cmd == SIOCGARP) {
err = -ENODEV;
goto out;
}


Here is a complete working program:

#include <stdlib.h>
#include <stdio.h>


#include <net/if_arp.h>
#include <sys/ioctl.h>
#include <netinet/in.h>

#include <arpa/inet.h>

int main(void)
{
struct sockaddr_in sin = { 0 };
struct arpreq myarp = { { 0 } };
int sockfd;

sin.sin_family = AF_INET;
inet_aton("10.10.10.1", &sin.sin_addr);

memcpy(&myarp.arp_pa, &sin, sizeof myarp.arp_pa);
strcpy(myarp.arp_dev, "eth0");

if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
return EXIT_FAILURE;
}

if (ioctl(sockfd, SIOCGARP, &myarp) == -1) {
perror("ioctl");
return EXIT_FAILURE;
}

/* do something with ioctl() results */

return EXIT_SUCCESS;
}

Frederic Pont

unread,
Jun 8, 1999, 3:00:00 AM6/8/99
to
Kaz,

Thanks for your complete and quick answer, but it's still not working..
Using your code, I get now this error message :

ioctl: Device not configured


> Here is a complete working program:
>
> #include <stdlib.h>
> #include <stdio.h>
> #include <net/if_arp.h>
> #include <sys/ioctl.h>
> #include <netinet/in.h>
> #include <arpa/inet.h>
>
> int main(void)
> {
> struct sockaddr_in sin = { 0 };
> struct arpreq myarp = { { 0 } };
> int sockfd;
>
> sin.sin_family = AF_INET;
> inet_aton("10.10.10.1", &sin.sin_addr);
>
> memcpy(&myarp.arp_pa, &sin, sizeof myarp.arp_pa);
> strcpy(myarp.arp_dev, "eth0");
>
> if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
> perror("socket");
> return EXIT_FAILURE;
> }
>
> if (ioctl(sockfd, SIOCGARP, &myarp) == -1) {
> perror("ioctl");
> return EXIT_FAILURE;
> }
>
> /* do something with ioctl() results */
>
> return EXIT_SUCCESS;
> }
>

Kaz Kylheku

unread,
Jun 9, 1999, 3:00:00 AM6/9/99
to
On Tue, 08 Jun 1999 21:37:26 GMT, Frederic Pont <freder...@epfl.ch> wrote:
>Kaz,
>
>Thanks for your complete and quick answer, but it's still not working..
>Using your code, I get now this error message :

I have the impression that there is some kind of mismatch between errnos and
the messages in glibc2.

The program runs fine on my glibc2/linux 2.2.9 system. If I change
eth0 to some non-existent ethernet, I get errno 19, which the library
interprets as ``operation not supported by device''. But according
to the kernel header file, the error is ENODEV, which is ``No such device''.
Glibc2 is emitting misleading error messages.

If I change the sought-after IP address to something that isn't in the
ARP cache, then I get error 6, with the ``Device not configured'' message.

>ioctl: Device not configured

This is what glibc2 yields for ENXIO, which is actually ``No such device or
address''. Neither error message accurately represents the actual error, though
``no address'' is closer in meaning.

The best thing to do with exotic kernel ioctl's is to look at the kernel
code, and trap all possible errors and convert them to meaningful
error messages or actions in your program. Don't rely on strerror()
because even if the message mapping is accurate, the generic messages
often don't describe the error condition accurately. In the
case of ENXIO returned from the SIOCGARP, you really want the message
``no hardware address found in the device's ARP cache corresponding
to the given network address''.

Frederic Pont

unread,
Jun 9, 1999, 3:00:00 AM6/9/99
to
Ooops..
The delay between the time I checked /proc/net/arp and the moment I
modified I run my program was just too long, and the ARP entry I was
looking for was just not in the ARP cache anymore... :-))
Your program is running fine.

Thanks again for your help.
Fred

In article <slrn7ltdh...@ashi.FootPrints.net>,

0 new messages