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:**:**:**:**:**