ioctl programming under kernel 2.6 series


by: Ev1lut10n  a.k.a Bocah Tua Nakal

~ Int Security Release ~

Gopher: gopher://sdf.org/1/users/ev1lut10

content :
- device controlling
- ioctl on socket


this article will show basics of ioctl usages .ioctl is a syscall commonly used for controlling devices under nix system.
This ioctl function can be in user space or kernel space.
on User Space this ioctl function is useful to perform some operations which can't be performed by other regular syscalls.
ioctl function used to control any devices i/o .. IOCTL = Device Input and the  Output Controller.
for more complete explanations just take a look : man ioctl.

have a good visit into my linux b0x:
============
ev1lut10n@ev1l:~$ cat /usr/include/sys/ioctl.h | grep 'int ioctl'
extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;
============

- considering above code the first parameter will be file descriptor number.
- and the second will be our device dependent request code, say it :  command !
- and for next argument as we may be untyped pointer in memory
since there are so many benefits of ioctl we will limit here only in 3 parts:

[Sample IOCTL Code in C]

1. Device Controlling

ok make sure u include our beloved header at /usr/include/sys/ioctl.h:
===================
#ifdef HAVE_SYS_IOCTL
#include  <sys/ioctl.h>
#endif
===================
#ifdef HAVE_SYS_IOCTL, where the ifdef directive is used to check whether we have ioctl or not.

there are some functions related to this ioctl() such as:
- open()
when u use this funct don't forget it needs  fcntl.h
======================================
root@mywisdom-Vostro1310:/usr/include# cat fcntl.h | grep 'open ('
extern int open (__const char *__file, int __oflag, ...) __nonnull ((1)
=======================================
this function mostly used to open a file descriptor before we use ioctl syscall

here is a simple example, ex you wanna open /dev/cdrom:

if(fd=open("/dev/cdrom",O_RDONLY))

so what's )_RDONLY. check out this flags desc below:
============================
O_RDONLY        Only read operations permitted
O_WRONLY        Only write operations permitted
O_RDWR          Read and Write operations both permitted
O_NONBLOCK      Non-blocking, applies to open operation only
O_APPEND        All writes go to end of file
O_CREAT         Create file if it doesn't already exist
O_TRUNC         Delete existing contents of file
O_EXCL          Open fails if file already exists
O_SHLOCK        Get a "shared lock" on the file
O_EXLOCK        Get an "exclusive lock" on the file
O_DIRECT        Try to avoid all caching of operations
O_FSYNC         All writes immediately effective, no buffering
O_NOFOLLOW      If file is symbolic link, open it, don't follow it

and the next parameter is optional where it's usually indicated the permissions

- close()
this will be used to close our FD that we've opened using open() func


Here's sample for stopping and ejecting the cdrom device:
====================
/**some cdrom operation using ioctl by ev1lut10n**/
#include <stdio.h>
#include <stdlib.h>
#include  <fcntl.h>
#include  <linux/cdrom.h>
#include  <sys/stat.h>
#include  <sys/types.h>
#include  <unistd.h>
#ifdef HAVE_SYS_IOCTL
#include  <sys/ioctl.h>
#endif
char menu();
int main ()
{
       int pilihan;
       int fd;
       fd=open ("/dev/cdrom", O_RDONLY);

       pilihan=menu();

       if(pilihan==97)
       {
                           fprintf(stdout,"\nStopping cdrom device.using ioctl syscall..\n");
                           ioctl  (fd, CDROMSTOP,0);
       }
       else
       {

                          fprintf(stdout,"\nEjecting cdrom device.using ioctl syscall..\n");
                           ioctl  (fd, CDROMEJECT,0);
       }
close (fd);
return 0;
}

char menu()
{
       char select_me;
       fprintf(stdout,"\nby: ev1lut10n");
       fprintf(stdout,"\nWatcha gonna do ?? (type a or b)\n");
       fprintf(stdout,"\na ---- stopping currently playing cd");
       fprintf(stdout,"\nb ---- eject cdrom ");
       fprintf(stdout,"\ntype a or b :");
       select_me=getchar();
       return select_me;
}

====================

AS u may see above we use 2 command for controlling cdrom device:
ioctl  (fd, CDROMSTOP,0);  where here we use ioctl syscall to stop our cdrom device
and
ioctl  (fd, CDROMEJECT,0);  where we use ioctl syscall to eject our cdrom device
before our ioctl we already have an open file descriptor :
============================
fd=open ("/dev/cdrom", O_RDONLY);
============================

where we've opened /dev/cdrom using  O_RDONLY flag


for more complete linux cdrom ioctl programming you may see any command related to this device at:
=======
root@ev1l:/home/mywisdom/c/ioctl# cat /usr/include/linux/cdrom.h | grep "#define CDROM"
#define CDROMPAUSE              0x5301 /* Pause Audio Operation */
#define CDROMRESUME             0x5302 /* Resume paused Audio Operation */
#define CDROMPLAYMSF            0x5303 /* Play Audio MSF (struct cdrom_msf) */
#define CDROMPLAYTRKIND         0x5304 /* Play Audio Track/index
#define CDROMREADTOCHDR         0x5305 /* Read TOC header
#define CDROMREADTOCENTRY       0x5306 /* Read TOC entry
#define CDROMSTOP               0x5307 /* Stop the cdrom drive */
#define CDROMSTART              0x5308 /* Start the cdrom drive */
#define CDROMEJECT              0x5309 /* Ejects the cdrom media */
#define CDROMVOLCTRL            0x530a /* Control output volume
#define CDROMSUBCHNL            0x530b /* Read subchannel data
#define CDROMREADMODE2          0x530c /* Read CDROM mode 2 data (2336 Bytes)
#define CDROMREADMODE1          0x530d /* Read CDROM mode 1 data (2048 Bytes)
#define CDROMREADAUDIO          0x530e /* (struct cdrom_read_audio) */
#define CDROMEJECT_SW           0x530f /* enable(1)/disable(0) auto-ejecting */
#define CDROMMULTISESSION       0x5310 /* Obtain the start-of-last-session
#define CDROM_GET_MCN           0x5311 /* Obtain the "Universal Product Code"
#define CDROM_GET_UPC           CDROM_GET_MCN  /* This one is deprecated,
#define CDROMRESET              0x5312 /* hard-reset the drive */
#define CDROMVOLREAD            0x5313 /* Get the drive's volume setting
#define CDROMREADRAW            0x5314  /* read data in raw mode (2352 Bytes)
#define CDROMREADCOOKED         0x5315  /* read data in cooked mode */
#define CDROMSEEK               0x5316  /* seek msf address */
#define CDROMPLAYBLK            0x5317  /* (struct cdrom_blk) */
#define CDROMREADALL            0x5318  /* read all 2646 bytes */
#define CDROMGETSPINDOWN        0x531d
#define CDROMSETSPINDOWN        0x531e
#define CDROMCLOSETRAY          0x5319  /* pendant of CDROMEJECT */
#define CDROM_SET_OPTIONS       0x5320  /* Set behavior options */
#define CDROM_CLEAR_OPTIONS     0x5321  /* Clear behavior options */
#define CDROM_SELECT_SPEED      0x5322  /* Set the CD-ROM speed */
#define CDROM_SELECT_DISC       0x5323  /* Select disc (for juke-boxes) */
#define CDROM_MEDIA_CHANGED     0x5325  /* Check is media changed  */
#define CDROM_DRIVE_STATUS      0x5326  /* Get tray position, etc. */
#define CDROM_DISC_STATUS       0x5327  /* Get disc type, etc. */
#define CDROM_CHANGER_NSLOTS    0x5328  /* Get number of slots */
#define CDROM_LOCKDOOR          0x5329  /* lock or unlock door */
#define CDROM_DEBUG             0x5330  /* Turn debug messages on/off */
#define CDROM_GET_CAPABILITY    0x5331  /* get capabilities */
#define CDROMAUDIOBUFSIZ        0x5382  /* set the audio buffer size */
#define CDROM_SEND_PACKET       0x5393  /* send a packet to the drive */
#define CDROM_NEXT_WRITABLE     0x5394  /* get next writable block */
#define CDROM_LAST_WRITTEN      0x5395  /* get last block written on disc */
======
the above sample we focus on kernel 2.6
and for those of you who getting interested for kernel 3.0 cdrom programing, you may also find uselful material at:
==============
http://www.mjmwired.net/kernel/Documentation/ioctl/cdrom.txt
==============

on success our ioctl function will return other than -1 !!!

2.  ioctl on socket

we also may use an ioctl syscall related to socket.
as i've mentioned above the call for ioctl : ioctl(any_file_descriptor, any_command, etc...).
in socket operation circumstances we've some common categories such as:
========
   * Socket, an ioctl request for controlling socket , ex cmd: SIOCATMARK, etc
   * Routing table, an ioctl req related to kernel routing table, ex: SIOCADDRT , SIOUPDROUTE, etc
   * ARP table, an ioctl req for modifying arp table, ex: SIOCSARP , SIOCDARP , etc
   * Interface, an ioctl req related to interface on ur fvcking system, ex: SIOCSIFADDR  (getting interface name), etc
=============

you can read more at  /usr/include/bits/ioctls.h :
========================================
/* Socket configuration controls. */
#define SIOCGIFNAME     0x8910          /* get iface name               */
#define SIOCSIFLINK     0x8911          /* set iface channel            */
#define SIOCGIFCONF     0x8912          /* get iface list               */
#define SIOCGIFFLAGS    0x8913          /* get flags                    */
#define SIOCSIFFLAGS    0x8914          /* set flags                    */
#define SIOCGIFADDR     0x8915          /* get PA address               */
#define SIOCSIFADDR     0x8916          /* set PA address               */
#define SIOCGIFDSTADDR  0x8917          /* get remote PA address        */
#define SIOCSIFDSTADDR  0x8918          /* set remote PA address        */
#define SIOCGIFBRDADDR  0x8919          /* get broadcast PA address     */
#define SIOCSIFBRDADDR  0x891a          /* set broadcast PA address     */
#define SIOCGIFNETMASK  0x891b          /* get network PA mask          */
#define SIOCSIFNETMASK  0x891c          /* set network PA mask          */
#define SIOCGIFMETRIC   0x891d          /* get metric                   */
#define SIOCSIFMETRIC   0x891e          /* set metric                   */
#define SIOCGIFMEM      0x891f          /* get memory address (BSD)     */
#define SIOCSIFMEM      0x8920          /* set memory address (BSD)     */
#define SIOCGIFMTU      0x8921          /* get MTU size                 */
#define SIOCSIFMTU      0x8922          /* set MTU size                 */
#define SIOCSIFNAME     0x8923          /* set interface name           */
#define SIOCSIFHWADDR   0x8924          /* set hardware address         */
#define SIOCGIFENCAP    0x8925          /* get/set encapsulations       */
#define SIOCSIFENCAP    0x8926
#define SIOCGIFHWADDR   0x8927          /* Get hardware address         */
#define SIOCGIFSLAVE    0x8929          /* Driver slaving support       */
#define SIOCSIFSLAVE    0x8930
#define SIOCADDMULTI    0x8931          /* Multicast address lists      */
#define SIOCDELMULTI    0x8932
#define SIOCGIFINDEX    0x8933          /* name -> if_index mapping     */
#define SIOGIFINDEX     SIOCGIFINDEX    /* misprint compatibility :-)   */
#define SIOCSIFPFLAGS   0x8934          /* set/get extended flags set   */
#define SIOCGIFPFLAGS   0x8935
#define SIOCDIFADDR     0x8936          /* delete PA address            */
#define SIOCSIFHWBROADCAST      0x8937  /* set hardware broadcast addr  */
#define SIOCGIFCOUNT    0x8938          /* get number of devices */
#define SIOCGIFBR       0x8940          /* Bridging support             */
#define SIOCSIFBR       0x8941          /* Set bridging options         */
#define SIOCGIFTXQLEN   0x8942          /* Get the tx queue length      */
#define SIOCSIFTXQLEN   0x8943          /* Set the tx queue length      */
and so on...............
===============================


[Interface]
ok when u wanna play with interface u must knowing some important structs and constants related to our fvcking interfaces, check this out:
some codes from /usr/include/net/if.h:
====================================
struct ifreq
 {
# define IFHWADDRLEN    6
# define IFNAMSIZ       IF_NAMESIZE
   union
     {
       char ifrn_name[IFNAMSIZ];       /* Interface name, e.g. "en0".  */
     } ifr_ifrn;

   union
     {
       struct sockaddr ifru_addr;
       struct sockaddr ifru_dstaddr;
       struct sockaddr ifru_broadaddr;
       struct sockaddr ifru_netmask;
       struct sockaddr ifru_hwaddr;
       short int ifru_flags;
       int ifru_ivalue;
       int ifru_mtu;
       struct ifmap ifru_map;
       char ifru_slave[IFNAMSIZ];      /* Just fits the size */
       char ifru_newname[IFNAMSIZ];
       __caddr_t ifru_data;
     } ifr_ifru;
 };
# define ifr_name       ifr_ifrn.ifrn_name      /* interface name       */
# define ifr_hwaddr     ifr_ifru.ifru_hwaddr    /* MAC address          */
# define ifr_addr       ifr_ifru.ifru_addr      /* address              */
# define ifr_dstaddr    ifr_ifru.ifru_dstaddr   /* other end of p-p lnk */
# define ifr_broadaddr  ifr_ifru.ifru_broadaddr /* broadcast address    */
# define ifr_netmask    ifr_ifru.ifru_netmask   /* interface net mask   */
# define ifr_flags      ifr_ifru.ifru_flags     /* flags                */
# define ifr_metric     ifr_ifru.ifru_ivalue    /* metric               */
# define ifr_mtu        ifr_ifru.ifru_mtu       /* mtu                  */
# define ifr_map        ifr_ifru.ifru_map       /* device map           */
# define ifr_slave      ifr_ifru.ifru_slave     /* slave device         */
# define ifr_data       ifr_ifru.ifru_data      /* for use by interface */
# define ifr_ifindex    ifr_ifru.ifru_ivalue    /* interface index      */
# define ifr_bandwidth  ifr_ifru.ifru_ivalue    /* link bandwidth       */
# define ifr_qlen       ifr_ifru.ifru_ivalue    /* queue length         */
# define ifr_newname    ifr_ifru.ifru_newname   /* New name             */
# define _IOT_ifreq     _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
# define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
# define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)


struct ifconf
 {
   int ifc_len;                        /* Size of buffer.  */
   union
     {
       __caddr_t ifcu_buf;
       struct ifreq *ifcu_req;
     } ifc_ifcu;
 };
# define ifc_buf        ifc_ifcu.ifcu_buf       /* Buffer address.  */
# define ifc_req        ifc_ifcu.ifcu_req       /* Array of structures.  */
# define _IOT_ifconf _IOT(_IOTS(struct ifconf),1,0,0,0,0) /* not right */
#endif  /* Misc.  */
======================================

or u can see use this cmd at ur fvcking shell: man netdevice

ok so we're gonna use those 2 fvcking struct, here we go with our c:
===================
struct ifreq *pIfr;
struct ifconf ifc;
===================

here more complete where we're gonna use to view our interface when we've created our socket file desc:
===========
/***this code taken from http://stackoverflow.com/questions/4961051/find-network-interfaces-that-are-not-running**/
#include  <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
   struct ifreq *pIfr;
   struct ifconf ifc;
   char buf[1024];
   int s, i, j;

   s = socket(AF_INET, SOCK_DGRAM, 0);
   if (s==-1)
       return -1;

   ifc.ifc_len = sizeof(buf);
   ifc.ifc_buf = buf;
   ioctl(s, SIOCGIFCONF, &ifc);

   pIfr = ifc.ifc_req;
   for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; pIfr++) {
       printf("name=%s\n", pIfr->ifr_name);
   }
   close(s);
   return 0;
}
==============

as you see, the result will be somethin like tis:
==========
mywisdom@mywisdom-Vostro1310:~/c/ioctl$ gcc -o soket2 soket2.c
mywisdom@mywisdom-Vostro1310:~/c/ioctl$ ./socket2
bash: ./socket2: No such file or directory
mywisdom@mywisdom-Vostro1310:~/c/ioctl$ ./soket2
name=lo
name=eth0
==========

ok let's have a look on some important lines:

on  s = socket(AF_INET, SOCK_DGRAM, 0);
it's where we prepare an open socket file descriptor

=======
   ifc.ifc_len = sizeof(buf);
========

as u may see on our ifconf struct:

=====================
struct ifconf
 {
   int ifc_len;                        /* Size of buffer.  */
=====================

as we've declared the struct before:
struct ifconf ifc;
so   ifc.ifc_len will be 1024 bytes

the most importand line on our ioctl request on that open socket file desc:
================
ioctl(s, SIOCGIFCONF, &ifc);
================

where we use this command: SIOCGIFCONF to get iface lists
===============
mywisdom@mywisdom-Vostro1310:~/c/ioctl$ cat /usr/include/bits/ioctls.h | grep SIOCGIFCONF
#define SIOCGIFCONF     0x8912          /* get iface list               */
===============

and final important step is when we do a for loop to get pIfr->ifr_name:
==================
  pIfr = ifc.ifc_req;
   for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; pIfr++) {
       printf("name=%s\n", pIfr->ifr_name);
   }
==============

[modifying linux kernel routing table]


have a look at ur linux kernel ip routing table:
============================
mywisdom@mywisdom-Vostro1310:~/c/ioctl$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
111.**.**.*     *               255.255.255.0   U     1      0        0 eth0
link-local      *               255.255.0.0     U     1000   0        0 eth0
default         111.**.**.*     0.0.0.0         UG    0      0        0 eth0

mywisdom@mywisdom-Vostro1310:~/c/ioctl$ cat /proc/net/arp
IP address       HW type     Flags       HW address            Mask     Device
111.**.**.*     0x1         0x2         ***************     *        eth0

root@mywisdom-Vostro1310:/home/mywisdom/c/ioctl# /usr/sbin/arp -a
? (111.**.**.*) at c4:**:**:**:**:** [ether] on eth0

well the cmd :"arp -a" reads from /dev/kmem to get the cache
ok we've some cmd's on our ioctl related to this arp game:
- SIOCSARP --- ioctl request intended to add an entry to our fvcking arp table
- SIOCDARP -- D==delete means our fvcking ioctl request is intended to delete an entry for our fvcking arp table
- SIOCGARP -- G= get means our fvcking ioctl request is intended to get an entry from our fvcking arp table

for SIOCSARP  and SIOCDARP  u need root privileges and for SIOCGARP  u don't need root privilege
the first one to do is getting an entry from the kernel IP routing table, so we'll need ioctl(fd, SIOCGARP,arg).

you need to have a visit on /usr/include/net/if_arp.h to understand
===========
root@mywisdom-Vostro1310:/home/mywisdom/c/ioctl# cat /usr/include/net/if_arp.h
/* Based on the 4.4BSD and Linux version of this file.  */

#ifndef _NET_IF_ARP_H

#define _NET_IF_ARP_H 1
#include <sys/cdefs.h>

#include <sys/types.h>
#include <sys/socket.h>

__BEGIN_DECLS

/* Some internals from deep down in the kernel.  */
#define MAX_ADDR_LEN    7


/* This structure defines an ethernet arp header.  */

/* ARP protocol opcodes. */
#define ARPOP_REQUEST   1               /* ARP request.  */
#define ARPOP_REPLY     2               /* ARP reply.  */
#define ARPOP_RREQUEST  3               /* RARP request.  */
#define ARPOP_RREPLY    4               /* RARP reply.  */
#define ARPOP_InREQUEST 8               /* InARP request.  */
#define ARPOP_InREPLY   9               /* InARP reply.  */
#define ARPOP_NAK       10              /* (ATM)ARP NAK.  */

/* See RFC 826 for protocol description.  ARP packets are variable
  in size; the arphdr structure defines the fixed-length portion.
  Protocol type values are the same as those for 10 Mb/s Ethernet.
  It is followed by the variable-sized fields ar_sha, arp_spa,
  arp_tha and arp_tpa in that order, according to the lengths
  specified.  Field names used correspond to RFC 826.  */

struct arphdr
 {
   unsigned short int ar_hrd;          /* Format of hardware address.  */
   unsigned short int ar_pro;          /* Format of protocol address.  */
   unsigned char ar_hln;               /* Length of hardware address.  */
   unsigned char ar_pln;               /* Length of protocol address.  */
   unsigned short int ar_op;           /* ARP opcode (command).  */
#if 0
   /* Ethernet looks like this : This bit is variable sized
      however...  */
   unsigned char __ar_sha[ETH_ALEN];   /* Sender hardware address.  */
   unsigned char __ar_sip[4];          /* Sender IP address.  */
   unsigned char __ar_tha[ETH_ALEN];   /* Target hardware address.  */
   unsigned char __ar_tip[4];          /* Target IP address.  */
#endif
 };


/* ARP protocol HARDWARE identifiers. */
#define ARPHRD_NETROM   0               /* From KA9Q: NET/ROM pseudo. */
#define ARPHRD_ETHER    1               /* Ethernet 10/100Mbps.  */
#define ARPHRD_EETHER   2               /* Experimental Ethernet.  */
#define ARPHRD_AX25     3               /* AX.25 Level 2.  */
#define ARPHRD_PRONET   4               /* PROnet token ring.  */
#define ARPHRD_CHAOS    5               /* Chaosnet.  */
#define ARPHRD_IEEE802  6               /* IEEE 802.2 Ethernet/TR/TB.  */
#define ARPHRD_ARCNET   7               /* ARCnet.  */
#define ARPHRD_APPLETLK 8               /* APPLEtalk.  */
#define ARPHRD_DLCI     15              /* Frame Relay DLCI.  */
#define ARPHRD_ATM      19              /* ATM.  */
#define ARPHRD_METRICOM 23              /* Metricom STRIP (new IANA id).  */
#define ARPHRD_IEEE1394 24              /* IEEE 1394 IPv4 - RFC 2734.  */
#define ARPHRD_EUI64            27              /* EUI-64.  */
#define ARPHRD_INFINIBAND       32              /* InfiniBand.  */

/* Dummy types for non ARP hardware */
#define ARPHRD_SLIP     256
#define ARPHRD_CSLIP    257
#define ARPHRD_SLIP6    258
#define ARPHRD_CSLIP6   259
#define ARPHRD_RSRVD    260             /* Notional KISS type.  */
#define ARPHRD_ADAPT    264
#define ARPHRD_ROSE     270
#define ARPHRD_X25      271             /* CCITT X.25.  */
#define ARPHRD_HWX25    272             /* Boards with X.25 in firmware.  */
#define ARPHRD_PPP      512
#define ARPHRD_CISCO    513             /* Cisco HDLC.  */
#define ARPHRD_HDLC     ARPHRD_CISCO
#define ARPHRD_LAPB     516             /* LAPB.  */
#define ARPHRD_DDCMP    517             /* Digital's DDCMP.  */
#define ARPHRD_RAWHDLC  518             /* Raw HDLC.  */

#define ARPHRD_TUNNEL   768             /* IPIP tunnel.  */
#define ARPHRD_TUNNEL6  769             /* IPIP6 tunnel.  */
#define ARPHRD_FRAD     770             /* Frame Relay Access Device.  */
#define ARPHRD_SKIP     771             /* SKIP vif.  */
#define ARPHRD_LOOPBACK 772             /* Loopback device.  */
#define ARPHRD_LOCALTLK 773             /* Localtalk device.  */
#define ARPHRD_FDDI     774             /* Fiber Distributed Data Interface. */
#define ARPHRD_BIF      775             /* AP1000 BIF.  */
#define ARPHRD_SIT      776             /* sit0 device - IPv6-in-IPv4.  */
#define ARPHRD_IPDDP    777             /* IP-in-DDP tunnel.  */
#define ARPHRD_IPGRE    778             /* GRE over IP.  */
#define ARPHRD_PIMREG   779             /* PIMSM register interface.  */
#define ARPHRD_HIPPI    780             /* High Performance Parallel I'face. */
#define ARPHRD_ASH      781             /* (Nexus Electronics) Ash.  */
#define ARPHRD_ECONET   782             /* Acorn Econet.  */
#define ARPHRD_IRDA     783             /* Linux-IrDA.  */
#define ARPHRD_FCPP     784             /* Point to point fibrechanel.  */
#define ARPHRD_FCAL     785             /* Fibrechanel arbitrated loop.  */
#define ARPHRD_FCPL     786             /* Fibrechanel public loop.  */
#define ARPHRD_FCFABRIC 787             /* Fibrechanel fabric.  */
#define ARPHRD_IEEE802_TR 800           /* Magic type ident for TR.  */
#define ARPHRD_IEEE80211 801            /* IEEE 802.11.  */
#define ARPHRD_IEEE80211_PRISM 802      /* IEEE 802.11 + Prism2 header.  */
#define ARPHRD_IEEE80211_RADIOTAP 803   /* IEEE 802.11 + radiotap header.  */
#define ARPHRD_IEEE802154 804           /* IEEE 802.15.4 header.  */
#define ARPHRD_IEEE802154_PHY 805       /* IEEE 802.15.4 PHY header.  */

#define ARPHRD_VOID       0xFFFF        /* Void type, nothing is known.  */
#define ARPHRD_NONE       0xFFFE        /* Zero header length.  */


/* ARP ioctl request.  */
struct arpreq
 {
   struct sockaddr arp_pa;             /* Protocol address.  */
   struct sockaddr arp_ha;             /* Hardware address.  */
   int arp_flags;                      /* Flags.  */
   struct sockaddr arp_netmask;        /* Netmask (only for proxy arps).  */
   char arp_dev[16];
 };

/* ARP Flag values.  */
#define ATF_COM         0x02            /* Completed entry (ha valid).  */
#define ATF_PERM        0x04            /* Permanent entry.  */
#define ATF_PUBL        0x08            /* Publish entry.  */
#define ATF_USETRAILERS 0x10            /* Has requested trailers.  */
#define ATF_NETMASK     0x20            /* Want to use a netmask (only
                                          for proxy entries).  */
#define ATF_DONTPUB     0x40            /* Don't answer this addresses.  */
#define ATF_MAGIC       0x80            /* Automatically added entry.  */


/* Support for the user space arp daemon, arpd.  */
#define ARPD_UPDATE     0x01
#define ARPD_LOOKUP     0x02
#define ARPD_FLUSH      0x03

struct arpd_request
 {
   unsigned short int req;             /* Request type.  */
   u_int32_t ip;                       /* IP address of entry.  */
   unsigned long int dev;              /* Device entry is tied to.  */
   unsigned long int stamp;
   unsigned long int updated;
   unsigned char ha[MAX_ADDR_LEN];     /* Hardware address.  */
 };

__END_DECLS

#endif  /* net/if_arp.h */
=====================

we'll use this struct:
=============
struct arpreq
 {
   struct sockaddr arp_pa;             /* Protocol address.  */
   struct sockaddr arp_ha;             /* Hardware address.  */
   int arp_flags;                      /* Flags.  */
   struct sockaddr arp_netmask;        /* Netmask (only for proxy arps).  */
   char arp_dev[16];
 };
=============

ok let's have a sample code that use this SIOCGARP ioctl, well as a sample of this func usage is to find our gateway mac addr .


don't forget to include the header needed:
=================
#include <errno.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <linux/sockios.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
====================

u should already notice that we've use: #include <net/if_arp.h> to include our arp struct

here are 3 structs that we are gonna use:
============
struct arpreq       areq;
struct sockaddr_in *sin;
struct in_addr      ipaddr;
============

where in order to execute ioctl  SIOCGARP properly we need this struct: struct arpreq   areq;


the code was taken from
http://forums.devshed.com/c-programming-42/how-to-get-properly-ehternet-mac-address-with-siocgarp-request-171811.html

gatewaymac.c :
============================
/**taken from http://forums.devshed.com/c-programming-42/how-to-get-properly-ehternet-mac-address-with-siocgarp-request-171811.html
**/
#include <errno.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <linux/sockios.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>



static char *ethernet_mactoa(struct sockaddr *addr)
{
       static char buff[256];
       unsigned char *ptr = (unsigned char *) addr->sa_data;

       sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] &
0377));

return (buff);

}


int main(int argc, char *argv[]) {
       int                 s;
       struct arpreq       areq;
       struct sockaddr_in *sin;
       struct in_addr      ipaddr;

       if (argc < 2 || argc > 2) {
               fprintf(stderr, "-- Usage: %s ipaddress\n", argv[0]);
               exit(1);
       }

       /* Get an internet domain socket. */
       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
               perror("socket");
               exit(1);
       }

       /* Make the ARP request. */
       memset(&areq, 0, sizeof(areq));
       sin = (struct sockaddr_in *) &areq.arp_pa;
       sin->sin_family = AF_INET;

       if (inet_aton(argv[1], &ipaddr) == 0) {
               fprintf(stderr, "-- Error: invalid numbers-and-dots IP address %s.\n",
                               argv[1]);
               exit(1);
       }

       sin->sin_addr = ipaddr;
       sin = (struct sockaddr_in *) &areq.arp_ha;
       sin->sin_family = ARPHRD_ETHER;

       strncpy(areq.arp_dev, "eth0", 15);

       if (ioctl(s, SIOCGARP, (caddr_t) &areq) == -1) {
               perror("-- Error: unable to make ARP request, error");
               exit(1);
       }
       printf("%s (%d) -> %s\n", argv[1], inet_ntoa(&((struct sockaddr_in *) &areq.arp_pa)->sin_addr), ethernet_mactoa(&areq.arp_ha));
       return 0;
}
===========================

let's have a check on our gateway's mac address:
===========
root@mywisdom-Vostro1310:/home/mywisdom/c/ioctl# ./gatewaymac 111.**.**.*
111.**.**.*  -> C4:**:**:**:**:**