4 * Portions credited to Yoichi Hariguchi
6 * Jared Davison (Lineo) j.davison@moreton.com.au
10 #include "llip_utils.h"
12 #include <sys/socket.h>
13 #include <linux/netdevice.h>
14 #include <linux/if_ether.h>
15 #include <linux/if_arp.h>
22 #define MAC_BCAST_ADDR "\xff\xff\xff\xff\xff\xff"
23 #define GRATUITOUS_ARPS 2
24 #define GRATUITOUS_ARP_SPACING 2 /* seconds*/
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) */
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);
45 int llip_sendGratuitousArps(char* device_name, u_long address, unsigned char *source_hw_addr[6])
48 struct sockaddr addr; /* for interface name */
50 struct arpMsg arp; /* arp message */
52 if (llip_openRawSocket(&s, ETH_P_ARP)==-1)
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));
62 for(i=0; i<GRATUITOUS_ARPS; i++)
64 if ( sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0 ) {
66 syslog(LOG_INFO, "sendto (sendGratuitousArp)");
68 syslog(LOG_INFO, "sendto : ");
72 sleep(GRATUITOUS_ARP_SPACING);
78 /*********************************************************
84 int llip_arpCheck(char* device_name, u_long test_addr, unsigned char *source_hw_addr, long timeout) {
86 int rv; /* return value (IP test_addr usage status */
87 struct sockaddr addr; /* for interface name */
93 rv = 1; /* initialise ip to unused status */
95 if (llip_openRawSocket(&s, ETH_P_ARP)==-1)
99 /* we should send up to four probes at two second intervals or until we receive a response to our 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));
106 if ( sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0 ) {
107 syslog(LOG_ERR,"sendto (arpCheck): ");
112 /* wait arp reply, and check it */
115 while ( timeout > 0 ) {
119 if ( select(s+1, &fdset, (fd_set *)NULL, (fd_set *)NULL, &tm) < 0 ) {
121 syslog(LOG_INFO,"select (arpCheck)");
123 rv = 0; /* address used */
125 if ( FD_ISSET(s, &fdset) ) {
126 if (recv(s, &arp, sizeof(arp), 0) < 0 ) {
128 syslog(LOG_INFO,"recv (arpCheck)");
130 rv = 0; /* address used */
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 */
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 */
149 timeout -= time(NULL) - prevTime;
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 */
176 int llip_openRawSocket (int *s, u_short type) {
179 if((*s = socket (AF_INET, SOCK_PACKET, htons (type))) == -1) {
181 syslog(LOG_ERR,"socket err : %s\n",strerr());
186 if(setsockopt (*s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval)) == -1) {
188 syslog(LOG_ERR,"setsockopt err : %s\n",strerr());
196 /* returns a socket file descriptor which should be passed into the CheckCollision function */
197 struct collisionMonitor* llip_SetupCollisionMonitor(void)
200 if (openRawSocket(&s, ETH_P_ARP)==-1)
207 struct collisionMonitor {
208 int s; /* socket for monitoring arps */
215 /* returns 0 if no collision, !=0 for collision */
216 int llip_CheckCollision(int collision_socket)
218 /* watch for collisions */
219 /* wait arp reply, and check it */
222 while ( timeout > 0 ) {
226 if ( select(s+1, &fdset, (fd_set *)NULL, (fd_set *)NULL, &tm) < 0 ) {
228 syslog(LOG_INFO,"select (arpCheck)");
230 rv = 0; /* address used */
232 if ( FD_ISSET(s, &fdset) ) {
233 if (recv(s, &arp, sizeof(arp), 0) < 0 ) {
235 syslog(LOG_INFO,"recv (arpCheck)");
237 rv = 0; /* address used */
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 */
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 */
256 timeout -= time(NULL) - prevTime;