OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / dhcpcd / llip_utils.c
1 /*
2  * llip_arp.c
3  *
4  * Portions credited to Yoichi Hariguchi
5  * 
6  * Jared Davison (Lineo) j.davison@moreton.com.au
7  */
8
9
10 #include "llip_utils.h"
11 #include <sys/time.h>
12 #include <sys/socket.h>
13 #include <linux/netdevice.h>
14 #include <linux/if_ether.h>
15 #include <linux/if_arp.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <syslog.h>
21
22 #define MAC_BCAST_ADDR  "\xff\xff\xff\xff\xff\xff"
23 #define GRATUITOUS_ARPS 2
24 #define GRATUITOUS_ARP_SPACING  2       /* seconds*/
25
26 struct arpMsg {
27         struct ethhdr ethhdr;                   /* Ethernet header */
28         u_short htype;                          /* hardware type (must be ARPHRD_ETHER) */
29         u_short ptype;                          /* protocol type (must be ETH_P_IP) */
30         u_char  hlen;                           /* hardware address length (must be 6) */
31         u_char  plen;                           /* protocol address length (must be 4) */
32         u_short operation;                      /* ARP opcode */
33         u_char  sHaddr[6];                      /* sender's hardware address */
34         u_char  sInaddr[4];                     /* sender's IP address */
35         u_char  tHaddr[6];                      /* target's hardware address */
36         u_char  tInaddr[4];                     /* target's IP address */
37         u_char  pad[18];                        /* pad for min. Ethernet payload (60 bytes) */
38 };
39
40 /* local prototypes */
41 void llip_mkArpMsg(int opcode, u_long tInaddr, u_char *tHaddr,
42                  u_long sInaddr, u_char *sHaddr, struct arpMsg *msg);
43 int llip_openRawSocket (int *s, u_short type);
44
45 int llip_sendGratuitousArps(char* device_name, u_long address, unsigned char *source_hw_addr[6]) 
46 {
47         int s;                          /* socket */
48         struct sockaddr addr;           /* for interface name */
49         int i;  /*counter*/
50         struct arpMsg   arp;            /* arp message */
51
52         if (llip_openRawSocket(&s, ETH_P_ARP)==-1)
53         {       
54                 return -1;
55         }
56
57         /* send two arps two seconds apart */
58         llip_mkArpMsg(ARPOP_REPLY, 0xffffffffU, MAC_BCAST_ADDR, address, (u_char*) source_hw_addr, &arp);
59         bzero(&addr, sizeof(addr));
60         strncpy(addr.sa_data, device_name, sizeof(addr.sa_data));
61
62         for(i=0; i<GRATUITOUS_ARPS; i++)
63         {
64                 if ( sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0 ) {
65 #if 0
66                         syslog(LOG_INFO, "sendto (sendGratuitousArp)");
67 #endif
68                         syslog(LOG_INFO, "sendto : ");
69                         close(s);
70                         return -1;
71                 }
72                 sleep(GRATUITOUS_ARP_SPACING);
73         }
74         close(s);
75         return 0;
76 }
77
78 /*********************************************************
79  * Function :  arpCheck
80  * retn:        1 addr free
81  *               addr used
82  *              -1 error
83  */
84 int llip_arpCheck(char* device_name, u_long test_addr, unsigned char *source_hw_addr, long timeout)  {
85         int     s;                      /* socket */
86         int     rv;                     /* return value (IP test_addr usage status */
87         struct sockaddr addr;           /* for interface name */
88         struct arpMsg   arp;
89         fd_set                  fdset;
90         struct timeval  tm;
91         time_t                  prevTime;
92
93         rv = 1; /* initialise ip to unused status */
94
95         if (llip_openRawSocket(&s, ETH_P_ARP)==-1)
96         {
97                 return -1;
98         }
99 /* we should send up to four probes at two second intervals or until we receive a response to our probe */
100
101         /* send arp probe */
102         llip_mkArpMsg(ARPOP_REQUEST, test_addr, MAC_BCAST_ADDR, 0 /* source=0.0.0.0 */, (u_char *) source_hw_addr, &arp);
103         bzero(&addr, sizeof(addr));
104         strncpy(addr.sa_data, device_name, sizeof(addr.sa_data));
105
106         if ( sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0 ) {
107                 syslog(LOG_ERR,"sendto (arpCheck): ");
108                 close(s);
109                 return -1;
110         }
111         
112         /* wait arp reply, and check it */
113         tm.tv_usec = 0;
114         time(&prevTime);
115         while ( timeout > 0 ) {
116                 FD_ZERO(&fdset);
117                 FD_SET(s, &fdset);
118                 tm.tv_sec  = timeout;
119                 if ( select(s+1, &fdset, (fd_set *)NULL, (fd_set *)NULL, &tm) < 0 ) {
120 #if 0
121                         syslog(LOG_INFO,"select (arpCheck)");
122 #endif
123                         rv = 0; /* address used */
124                 }
125                 if ( FD_ISSET(s, &fdset) ) {
126                         if (recv(s, &arp, sizeof(arp), 0) < 0 ) {
127 #if 0
128                                 syslog(LOG_INFO,"recv (arpCheck)");
129 #endif
130                                 rv = 0; /* address used */
131                         }
132
133                         /* Receive response to our arp probe from a host configured with the IP  */
134                         if(arp.operation == htons(ARPOP_REPLY) && memcmp(arp.tHaddr, source_hw_addr, 6) == 0 && *((u_int *)arp.sInaddr) == test_addr ) {
135                                 rv = 0; /* address used */
136                                 break;
137                         }
138
139                         /* Watch for other ARP probes for the same address originating from other hosts while
140                            waiting for response to our ARP probe. This should help out in the situation
141                            where two or more hosts by chance attempt to configure the same IP address.
142                            If we receive an ARP probe for the same IP address from another hardware address
143                            then we return the fact the address is used */
144                         if(arp.operation == htons(ARPOP_REPLY) && memcmp(arp.ethhdr.h_dest, MAC_BCAST_ADDR, 6) == 0 && *((u_int *)arp.tInaddr) == test_addr && *((u_int *) arp.sInaddr) == 0 ) {
145                                 rv = 0;  /* address used - race condition caught */
146                                 break;
147                         }
148                 }
149                 timeout -= time(NULL) - prevTime;
150                 time(&prevTime);
151         }
152         close(s);
153         return rv;
154 }
155
156 void llip_mkArpMsg(int opcode, u_long tInaddr, u_char *tHaddr,
157                  u_long sInaddr, u_char *sHaddr, struct arpMsg *msg) {
158         bzero(msg, sizeof(*msg));
159         bcopy(tHaddr, msg->ethhdr.h_dest, 6); /* MAC DA */
160         bcopy(sHaddr, msg->ethhdr.h_source, 6); /* MAC SA */
161         msg->ethhdr.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */
162         msg->htype = htons(ARPHRD_ETHER);               /* hardware type */
163         msg->ptype = htons(ETH_P_IP);                   /* protocol type (ARP message) */
164         msg->hlen = 6;                                                  /* hardware address length */
165         msg->plen = 4;                                                  /* protocol address length */
166         msg->operation = htons(opcode);                 /* ARP op code */
167         *((u_int *)msg->sInaddr) = sInaddr;             /* source IP address */
168         bcopy(sHaddr, msg->sHaddr, 6);                  /* source hardware address */
169         *((u_int *)msg->tInaddr) = tInaddr;             /* target IP address */
170         if ( opcode == ARPOP_REPLY ) {
171                 bcopy(tHaddr, msg->tHaddr, 6);          /* target hardware address */
172         }
173 }
174
175
176 int llip_openRawSocket (int *s, u_short type) {
177         int optval = 1;
178
179         if((*s = socket (AF_INET, SOCK_PACKET, htons (type))) == -1) {
180 #if 0
181                 syslog(LOG_ERR,"socket err : %s\n",strerr());
182 #endif
183                 return -1;
184         }
185         
186         if(setsockopt (*s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval)) == -1) {
187 #if 0
188                 syslog(LOG_ERR,"setsockopt err : %s\n",strerr());
189 #endif
190                 return -1;
191     }
192 }
193
194
195 #if 0
196 /* returns a socket file descriptor which should be passed into the CheckCollision function */
197 struct collisionMonitor* llip_SetupCollisionMonitor(void)
198 {
199         int s;
200         if (openRawSocket(&s, ETH_P_ARP)==-1)
201                 return NULL;
202         else
203         {
204                 return s;
205         }
206 }
207 struct collisionMonitor {
208         int             s;              /* socket for monitoring arps */
209         long            timeout;
210         fd_set          fdset;
211         struct timeval  tm;
212         time_t          prevTime;
213 }
214
215 /* returns 0 if no collision, !=0 for collision */
216 int llip_CheckCollision(int collision_socket)
217 {
218         /* watch for collisions */
219         /* wait arp reply, and check it */
220         tm.tv_usec = 0;
221         time(&prevTime);
222         while ( timeout > 0 ) {
223                 FD_ZERO(&fdset);
224                 FD_SET(s, &fdset);
225                 tm.tv_sec  = timeout;
226                 if ( select(s+1, &fdset, (fd_set *)NULL, (fd_set *)NULL, &tm) < 0 ) {
227 #if 0
228                         syslog(LOG_INFO,"select (arpCheck)");
229 #endif
230                         rv = 0; /* address used */
231                 }
232                 if ( FD_ISSET(s, &fdset) ) {
233                         if (recv(s, &arp, sizeof(arp), 0) < 0 ) {
234 #if 0
235                                 syslog(LOG_INFO,"recv (arpCheck)");
236 #endif
237                                 rv = 0; /* address used */
238                         }
239
240                         /* Receive response to our arp probe from a host configured with the IP  */
241                         if(arp.operation == htons(ARPOP_REPLY) && memcmp(arp.tHaddr, source_hw_addr, 6) == 0 && *((u_int *)arp.sInaddr) == test_addr ) {
242                                 rv = 0; /* address used */
243                                 break;
244                         }
245
246                         /* Watch for other ARP probes for the same address originating from other hosts while
247                            waiting for response to our ARP probe. This should help out in the situation
248                            where two or more hosts by chance attempt to configure the same IP address.
249                            If we receive an ARP probe for the same IP address from another hardware address
250                            then we return the fact the address is used */
251                         if(arp.operation == htons(ARPOP_REPLY) && memcmp(arp.ethhdr.h_dest, MAC_BCAST_ADDR, 6) == 0 && *((u_int *)arp.tInaddr) == test_addr && *((u_int *) arp.sInaddr) == 0 ) {
252                                 rv = 0;  /* address used - race condition caught */
253                                 break;
254                         }
255                 }
256                 timeout -= time(NULL) - prevTime;
257                 time(&prevTime);
258         }
259
260 }
261 #endif