* fixes fro fixes from Sven-Ola
[olsrd.git] / lib / bmf / src / NetworkInterfaces.c
1 /*
2  * OLSR Basic Multicast Forwarding (BMF) plugin.
3  * Copyright (c) 2005, 2006, Thales Communications, Huizen, The Netherlands.
4  * Written by Erik Tromp.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without 
8  * modification, are permitted provided that the following conditions 
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright 
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright 
14  *   notice, this list of conditions and the following disclaimer in 
15  *   the documentation and/or other materials provided with the 
16  *   distribution.
17  * * Neither the name of Thales, BMF nor the names of its 
18  *   contributors may be used to endorse or promote products derived 
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
24  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
28  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
29  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /* -------------------------------------------------------------------------
34  * File       : NetworkInterfaces.c
35  * Description: Functions to open and close sockets
36  * Created    : 29 Jun 2006
37  *
38  * $Id: NetworkInterfaces.c,v 1.3 2007/02/11 11:51:56 bernd67 Exp $ 
39  * ------------------------------------------------------------------------- */
40
41 #include "NetworkInterfaces.h"
42
43 /* System includes */
44 #include <syslog.h> /* syslog() */
45 #include <string.h> /* strerror(), strchr(), strcmp() */
46 #include <errno.h> /* errno */
47 #include <unistd.h> /* close() */
48 #include <sys/ioctl.h> /* ioctl() */
49 #include <fcntl.h> /* fcntl() */
50 #include <assert.h> /* assert() */
51 #include <net/if.h> /* socket(), ifreq, if_indextoname(), if_nametoindex() */
52 #include <netinet/in.h> /* htons() */
53 #include <linux/if_ether.h> /* ETH_P_ALL */
54 #include <linux/if_packet.h> /* packet_mreq, PACKET_MR_PROMISC, PACKET_ADD_MEMBERSHIP */
55 #include <linux/if_tun.h> /* IFF_TAP */
56 #include <netinet/ip.h> /* struct ip */
57 #include <netinet/udp.h> /* SOL_UDP */
58
59 /* OLSRD includes */
60 #include "olsr.h" /* olsr_printf() */
61 #include "defs.h" /* olsr_cnf */
62 #include "local_hna_set.h" /* add_local_hna4_entry() */
63
64 /* Plugin includes */
65 #include "Packet.h" /* IFHWADDRLEN */
66 #include "Bmf.h" /* PLUGIN_NAME */
67 #include "Address.h" /* IsMulticast() */
68
69 /* List of network interface objects used by BMF plugin */
70 struct TBmfInterface* BmfInterfaces = NULL;
71
72 /* Highest-numbered open socket file descriptor. To be used as first
73  * parameter in calls to select(...). */
74 int HighestSkfd = -1;
75
76 /* Set of socket file descriptors */
77 fd_set InputSet;
78
79 /* File descriptor of EtherTunTap interface */
80 int EtherTunTapFd = -1;
81
82 /* Network interface name of EtherTunTap interface. May be overruled by
83  * setting the plugin parameter "BmfInterface". */
84 char EtherTunTapIfName[IFNAMSIZ] = "bmf0";
85
86 /* If the plugin parameter "BmfInterfaceType" is set to "tap", an
87  * EtherTap interface will be used, and this variable will be set to TT_TAP. If
88  * "BmfInterfaceType" is set to "tun" or not set at all, an IP tunnel interface 
89  * used, and this variable will be set to TT_TUN. */
90 enum TTunOrTap TunOrTap = TT_TUN;
91
92 #define ETHERTUNTAPIPNOTSET 0
93
94 /* 10.255.255.253 in host byte order */
95 #define ETHERTUNTAPDEFAULTIP 0x0AFFFFFD
96
97 /* The IP address of the BMF network interface in host byte order.
98  * May be overruled by setting the plugin parameter "BmfInterfaceIp". */
99 u_int32_t EtherTunTapIp = ETHERTUNTAPIPNOTSET;
100
101 /* 255.255.255.255 in host byte order. May be overruled by
102  * setting the plugin parameter "BmfInterfaceIp". */
103 u_int32_t EtherTunTapIpMask = 0xFFFFFFFF;
104
105 /* The IP broadcast address of the BMF network interface in host byte order.
106  * May be overruled by setting the plugin parameter "BmfinterfaceIp". */
107 u_int32_t EtherTunTapIpBroadcast = ETHERTUNTAPDEFAULTIP;
108
109 /* Whether or not the configuration has overruled the default IP
110  * configuration of the EtherTunTap interface */
111 int TunTapIpOverruled = 0;
112
113 /* Whether or not to capture packets on the OLSR-enabled
114  * interfaces (in promiscuous mode). May be overruled by setting the plugin
115  * parameter "CapturePacketsOnOlsrInterfaces" to "yes". */
116 int CapturePacketsOnOlsrInterfaces = 0;
117
118 /* -------------------------------------------------------------------------
119  * Function   : SetBmfInterfaceName
120  * Description: Overrule the default network interface name ("bmf0") of the
121  *              EtherTunTap interface
122  * Input      : ifname - network interface name (e.g. "mybmf0")
123  * Output     : none
124  * Return     : fail (0) or success (1)
125  * Data Used  : none
126  * ------------------------------------------------------------------------- */
127 int SetBmfInterfaceName(const char* ifname)
128 {
129   strncpy(EtherTunTapIfName, ifname, IFNAMSIZ - 1);
130   EtherTunTapIfName[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
131   return 1;
132 }
133
134 /* -------------------------------------------------------------------------
135  * Function   : SetBmfInterfaceType
136  * Description: Overrule the default network interface type ("tun") of the
137  *              EtherTunTap interface
138  * Input      : iftype - network interface type, either "tun" or "tap"
139  * Output     : none
140  * Return     : fail (0) or success (1)
141  * Data Used  : none
142  * ------------------------------------------------------------------------- */
143 int SetBmfInterfaceType(const char* iftype)
144 {
145   if (strcmp(iftype, "tun") == 0)
146   {
147     TunOrTap = TT_TUN;
148     return 1;
149   }
150   else if (strcmp(iftype, "tap") == 0)
151   {
152     TunOrTap = TT_TAP;
153     return 1;
154   }
155
156   /* Value not recognized */
157   return 0;
158 }
159
160 /* -------------------------------------------------------------------------
161  * Function   : SetBmfInterfaceIp
162  * Description: Overrule the default IP address and prefix length
163  *              ("10.255.255.253/30") of the EtherTunTap interface
164  * Input      : ip - IP address, followed by '/' and prefix length
165  * Output     : none
166  * Return     : fail (0) or success (1)
167  * Data Used  : none
168  * ------------------------------------------------------------------------- */
169 int SetBmfInterfaceIp(const char* ip)
170 {
171 #define IPV4_MAX_ADDRLEN 16
172 #define IPV4_MAX_PREFIXLEN 32
173   char* slashAt;
174   char ipAddr[IPV4_MAX_ADDRLEN];
175   struct in_addr sinaddr;
176   int prefixLen;
177   int i;
178
179   /* Inspired by function str2prefix_ipv4 as found in Quagga source
180    * file lib/prefix.c */
181
182   /* Find slash inside string. */
183   slashAt = strchr(ip, '/');
184
185   /* String doesn't contain slash. */
186   if (slashAt == NULL || slashAt - ip >= IPV4_MAX_ADDRLEN)
187   {
188     /* No prefix length specified, or IP address too long */
189     return 0;
190   }
191
192   strncpy(ipAddr, ip, slashAt - ip);
193   *(ipAddr + (slashAt - ip)) = '\0';
194   if (inet_aton(ipAddr, &sinaddr) == 0)
195   {
196     /* Invalid address passed */
197     return 0;
198   }
199
200   EtherTunTapIp = ntohl(sinaddr.s_addr);
201
202   /* Get prefix length. */
203   prefixLen = atoi(++slashAt);
204   if (prefixLen <= 0 || prefixLen > IPV4_MAX_PREFIXLEN)
205   {
206           return 0;
207         }
208
209   /* Compose IP subnet mask in host byte order */
210   EtherTunTapIpMask = 0;
211   for (i = 0; i < prefixLen; i++)
212   {
213     EtherTunTapIpMask |= (1 << (IPV4_MAX_PREFIXLEN - 1 - i));
214   }
215
216   /* Compose IP broadcast address in host byte order */
217   EtherTunTapIpBroadcast = EtherTunTapIp;
218   for (i=prefixLen; i < IPV4_MAX_PREFIXLEN; i++)
219   {
220     EtherTunTapIpBroadcast |= (1 << (IPV4_MAX_PREFIXLEN - 1 - i));
221   }
222
223   TunTapIpOverruled = 1;
224
225   return 1;
226 }
227
228 /* -------------------------------------------------------------------------
229  * Function   : SetCapturePacketsOnOlsrInterfaces
230  * Description: Overrule the default setting, enabling or disabling the
231  *              capturing of packets on OLSR-enabled interfaces.
232  * Input      : enable - either "yes" or "no"
233  * Output     : none
234  * Return     : fail (0) or success (1)
235  * Data Used  : none
236  * ------------------------------------------------------------------------- */
237 int SetCapturePacketsOnOlsrInterfaces(const char* enable)
238 {
239   if (strcmp(enable, "yes") == 0)
240   {
241     CapturePacketsOnOlsrInterfaces = 1;
242     return 1;
243   }
244   else if (strcmp(enable, "no") == 0)
245   {
246     CapturePacketsOnOlsrInterfaces = 0;
247     return 1;
248   }
249
250   /* Value not recognized */
251   return 0;
252 }
253
254 /* To save the state of the IP spoof filter for the EtherTunTap interface */
255 static char EthTapSpoofState = '1';
256
257 /* -------------------------------------------------------------------------
258  * Function   : DeactivateSpoofFilter
259  * Description: Deactivates the Linux anti-spoofing filter for the tuntap
260  *              interface
261  * Input      : tunTapName - name used for the tuntap interface (e.g. "tun0" or "tap1")
262  * Output     : none
263  * Return     : fail (0) or success (1)
264  * Data Used  : EthTapSpoofState
265  * Notes      : Saves the current filter state for later restoring
266  * ------------------------------------------------------------------------- */
267 static int DeactivateSpoofFilter(const char* tunTapName)
268 {
269   FILE* procSpoof;
270   char procFile[FILENAME_MAX];
271
272   assert(tunTapName != NULL);
273
274   /* Generate the procfile name */
275   sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", tunTapName);
276
277   /* Open procfile for reading */
278   procSpoof = fopen(procFile, "r");
279   if (procSpoof == NULL)
280   {
281     fprintf(
282       stderr,
283       "WARNING! Could not open the %s file to check/disable the IP spoof filter!\n"
284       "Are you using the procfile filesystem?\n"
285       "Does your system support IPv4?\n"
286       "I will continue (in 3 sec) - but you should manually ensure that IP spoof\n"
287       "filtering is disabled!\n\n",
288       procFile);
289       
290     sleep(3);
291     return 0;
292   }
293
294   EthTapSpoofState = fgetc(procSpoof);
295   fclose(procSpoof);
296
297   /* Open procfile for writing */
298   procSpoof = fopen(procFile, "w");
299   if (procSpoof == NULL)
300   {
301     fprintf(stderr, "Could not open %s for writing!\n", procFile);
302     fprintf(
303       stderr,
304       "I will continue (in 3 sec) - but you should manually ensure that IP"
305       " spoof filtering is disabled!\n\n");
306     sleep(3);
307     return 0;
308   }
309
310   syslog(LOG_INFO, "Writing \"0\" to %s", procFile);
311   fputs("0", procSpoof);
312
313   fclose(procSpoof);
314
315   return 1;
316 }
317
318 /* -------------------------------------------------------------------------
319  * Function   : RestoreSpoofFilter
320  * Description: Restores the Linux anti-spoofing filter setting for the tuntap
321  *              interface
322  * Input      : tunTapName - name used for the tuntap interface (e.g. "tun0" or "tap1")
323  * Output     : none
324  * Return     : none
325  * Data Used  : EthTapSpoofState
326  * ------------------------------------------------------------------------- */
327 static void RestoreSpoofFilter(const char* tunTapName)
328 {
329   FILE* procSpoof;
330   char procFile[FILENAME_MAX];
331
332   assert(tunTapName != NULL);
333
334   /* Generate the procfile name */
335   sprintf(procFile, "/proc/sys/net/ipv4/conf/%s/rp_filter", tunTapName);
336
337   /* Open procfile for writing */
338   procSpoof = fopen(procFile, "w");
339   if (procSpoof == NULL)
340   {
341     fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procFile);
342   }
343   else
344   {
345     syslog(LOG_INFO, "Resetting %s to %c\n", procFile, EthTapSpoofState);
346
347     fputc(EthTapSpoofState, procSpoof);
348     fclose(procSpoof);
349   }
350 }
351
352 /* -------------------------------------------------------------------------
353  * Function   : CreateCaptureSocket
354  * Description: Create socket for promiscuously capturing multicast IP traffic
355  * Input      : ifname - network interface (e.g. "eth0")
356  * Output     : none
357  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
358  * Data Used  : none
359  * Notes      : The socket is a raw packet socket, bound to the specified
360  *              network interface
361  * ------------------------------------------------------------------------- */
362 static int CreateCaptureSocket(const char* ifName)
363 {
364   int ifIndex = if_nametoindex(ifName);
365   struct packet_mreq mreq;
366   struct ifreq req;
367   struct sockaddr_ll bindTo;
368
369   /* Open raw packet socket */
370   int skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
371   if (skfd < 0)
372   {
373     olsr_printf(1, "%s: socket(PF_PACKET) error: %s\n", PLUGIN_NAME, strerror(errno));
374     return -1;
375   }
376
377   /* Set interface to promiscuous mode */
378   memset(&mreq, 0, sizeof(struct packet_mreq));
379   mreq.mr_ifindex = ifIndex;
380   mreq.mr_type = PACKET_MR_PROMISC;
381   if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
382   {
383     olsr_printf(1, "%s: setsockopt(PACKET_MR_PROMISC) error: %s\n", PLUGIN_NAME, strerror(errno));
384     close(skfd);
385     return -1;
386   }
387
388   /* Get hardware (MAC) address */
389   memset(&req, 0, sizeof(struct ifreq));
390   strncpy(req.ifr_name, ifName, IFNAMSIZ - 1);
391   req.ifr_name[IFNAMSIZ-1] = '\0'; /* Ensures null termination */
392   if (ioctl(skfd, SIOCGIFHWADDR, &req) < 0)
393   {
394     olsr_printf(1, "%s: error retrieving MAC address: %s\n", PLUGIN_NAME, strerror(errno));
395     close(skfd);
396     return -1;
397   }
398    
399   /* Bind the socket to the specified interface */
400   memset(&bindTo, 0, sizeof(bindTo));
401   bindTo.sll_protocol = htons(ETH_P_ALL);
402   bindTo.sll_ifindex = ifIndex;
403   bindTo.sll_family = AF_PACKET;
404   memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
405   bindTo.sll_halen = IFHWADDRLEN;
406     
407   if (bind(skfd, (struct sockaddr*)&bindTo, sizeof(bindTo)) < 0)
408   {
409     olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno));
410     close(skfd);
411     return -1;
412   }
413
414   /* Set socket to blocking operation */
415   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0)
416   {
417     olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno));
418     close(skfd);
419     return -1;
420   }
421
422   /* Keep the highest-numbered descriptor */
423   if (skfd > HighestSkfd)
424   {
425     HighestSkfd = skfd;
426   }
427
428   /* Add descriptor to input set */
429   FD_SET(skfd, &InputSet);
430
431   return skfd;
432 }
433
434 /* -------------------------------------------------------------------------
435  * Function   : CreateEncapsulateSocket
436  * Description: Create a socket for sending and receiving encapsulated
437  *              multicast packets
438  * Input      : ifname - network interface (e.g. "eth0")
439  * Output     : none
440  * Return     : the socket descriptor ( >= 0), or -1 if an error occurred
441  * Data Used  : none
442  * Notes      : The socket is an UDP (datagram) over IP socket, bound to the
443  *              specified network interface
444  * ------------------------------------------------------------------------- */
445 static int CreateEncapsulateSocket(const char* ifName)
446 {
447   int on = 1;
448   struct sockaddr_in bindTo;
449
450   /* Open UDP-IP socket */
451   int skfd = socket(PF_INET, SOCK_DGRAM, 0);
452   if (skfd < 0)
453   {
454     olsr_printf(1, "%s: socket(PF_INET) error: %s\n", PLUGIN_NAME, strerror(errno));
455     return -1;
456   }
457
458   /* Enable sending to broadcast addresses */
459   if (setsockopt(skfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
460   {
461     olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno));
462     close(skfd);
463     return -1;
464   }
465         
466   /* Bind to the specific network interfaces indicated by ifName. */
467   /* When using Kernel 2.6 this must happer prior to the port binding! */
468   if (setsockopt(skfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, strlen(ifName) + 1) < 0)
469   {
470     olsr_printf(1, "%s: setsockopt() error: %s\n", PLUGIN_NAME, strerror(errno));
471     close(skfd);
472     return -1;
473   }
474
475   /* Bind to port */
476   memset(&bindTo, 0, sizeof(bindTo));
477   bindTo.sin_family = AF_INET;
478   bindTo.sin_port = htons(BMF_ENCAP_PORT);
479   bindTo.sin_addr.s_addr = htonl(INADDR_ANY);
480       
481   if (bind(skfd, (struct sockaddr*)&bindTo, sizeof(bindTo)) < 0) 
482   {
483     olsr_printf(1, "%s: bind() error: %s\n", PLUGIN_NAME, strerror(errno));
484     close(skfd);
485     return -1;
486   }
487
488   /* Set socket to blocking operation */
489   if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0)
490   {
491     olsr_printf(1, "%s: fcntl() error: %s\n", PLUGIN_NAME, strerror(errno));
492     close(skfd);
493     return -1;
494   }
495
496   /* Keep the highest-numbered descriptor */
497   if (skfd > HighestSkfd)
498   {
499     HighestSkfd = skfd;
500   }
501
502   /* Add descriptor to input set */
503   FD_SET(skfd, &InputSet);
504
505   return skfd;
506 }
507
508 /* -------------------------------------------------------------------------
509  * Function   : CreateLocalEtherTunTap
510  * Description: Creates and brings up an EtherTunTap interface
511  * Input      : none
512  * Output     : none
513  * Return     : the socket file descriptor (>= 0), or -1 in case of failure
514  * Data Used  : EtherTunTapIfName - name used for the tuntap interface (e.g.
515  *                "bmf0")
516  *              EtherTunTapIp
517  *              EtherTunTapIpMask
518  *              EtherTunTapIpBroadcast
519  *              BmfInterfaces
520  * Note       : Order dependency: call this function only if BmfInterfaces
521  *              is filled with a list of network interfaces.
522  * ------------------------------------------------------------------------- */
523 static int CreateLocalEtherTunTap(void)
524 {
525   static char* deviceName = "/dev/net/tun";
526   struct ifreq ifreq;
527   int etfd;
528   int ioctl_s;
529   int ioctlres;
530
531   etfd = open(deviceName, O_RDWR | O_NONBLOCK);
532   if (etfd < 0)
533   {
534     olsr_printf(1, "%s: error opening %s: %s\n", PLUGIN_NAME, deviceName, strerror(errno));
535     return -1;
536   }
537
538   memset(&ifreq, 0, sizeof(ifreq));
539   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
540   ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
541
542   /* Specify either the IFF_TAP flag for Ethernet frames, or the IFF_TUN flag for IP.
543    * Specify IFF_NO_PI for not receiving extra meta packet information. */
544   if (TunOrTap == TT_TUN)
545   {
546     ifreq.ifr_flags = IFF_TUN;
547   }
548   else
549   {
550     ifreq.ifr_flags = IFF_TAP;
551   }
552   ifreq.ifr_flags |= IFF_NO_PI;
553
554   if (ioctl(etfd, TUNSETIFF, (void *)&ifreq) < 0)
555   {
556     olsr_printf(1, "%s: ioctl(TUNSETIFF) error on %s: %s\n", PLUGIN_NAME, deviceName, strerror(errno));
557     close(etfd);
558     return -1;
559   }
560
561   memset(&ifreq, 0, sizeof(ifreq));
562   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
563   ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
564   ifreq.ifr_addr.sa_family = AF_INET;
565
566   ioctl_s = socket(PF_INET, SOCK_DGRAM, 0);
567   if (ioctl_s < 0)
568   {
569     olsr_printf(1, "%s: socket(PF_INET) error on %s: %s\n", PLUGIN_NAME, deviceName, strerror(errno));
570     close(etfd);
571     return -1;
572   }
573
574   /* Give the EtherTunTap interface an IP address.
575    * The default IP address is the address of the first OLSR interface;
576    * the default netmask is 255.255.255.255 . Having an all-ones netmask prevents
577    * automatic entry of the BMF network interface in the routing table. */
578   if (EtherTunTapIp == ETHERTUNTAPIPNOTSET)
579   {
580     struct TBmfInterface* nextBmfIf = BmfInterfaces;
581     while (nextBmfIf != NULL)
582     {
583       struct TBmfInterface* bmfIf = nextBmfIf;
584       nextBmfIf = bmfIf->next;
585
586       if (bmfIf->olsrIntf != NULL)
587       {
588         EtherTunTapIp = ntohl(((struct sockaddr_in*)&bmfIf->intAddr)->sin_addr.s_addr);
589         EtherTunTapIpBroadcast = EtherTunTapIp;
590       }
591     }
592   }
593
594   if (EtherTunTapIp == ETHERTUNTAPIPNOTSET)
595   {
596     /* No IP address configured for BMF network interface, and no OLSR interface found to
597      * copy IP address from. Fall back to default: 10.255.255.253 . */
598     EtherTunTapIp = ETHERTUNTAPDEFAULTIP;
599   }
600
601   ((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr.s_addr = htonl(EtherTunTapIp);
602   ioctlres = ioctl(ioctl_s, SIOCSIFADDR, &ifreq);
603   if (ioctlres >= 0)
604   {
605     /* Set net mask */
606     ((struct sockaddr_in*)&ifreq.ifr_netmask)->sin_addr.s_addr = htonl(EtherTunTapIpMask);
607     ioctlres = ioctl(ioctl_s, SIOCSIFNETMASK, &ifreq);
608     if (ioctlres >= 0)
609     {
610       /* Set broadcast IP */
611       ((struct sockaddr_in*)&ifreq.ifr_broadaddr)->sin_addr.s_addr = htonl(EtherTunTapIpBroadcast);
612       ioctlres = ioctl(ioctl_s, SIOCSIFBRDADDR, &ifreq);
613       if (ioctlres >= 0)
614       {
615         /* Bring EtherTunTap interface up (if not already) */
616         ioctlres = ioctl(ioctl_s, SIOCGIFFLAGS, &ifreq);
617         if (ioctlres >= 0)
618         {
619           ifreq.ifr_flags |= (IFF_UP | IFF_RUNNING | IFF_BROADCAST);
620           ioctlres = ioctl(ioctl_s, SIOCSIFFLAGS, &ifreq);
621         }
622       }
623     }
624   }
625
626   if (ioctlres < 0)
627   {
628     /* Any of the above ioctl() calls failed */
629     olsr_printf(
630       1,
631       "%s: error bringing up EtherTunTap interface \"%s\": %s\n",
632       PLUGIN_NAME,
633       EtherTunTapIfName,
634       strerror(errno));
635
636     close(etfd);
637     close(ioctl_s);
638     return -1;
639   } /* if (ioctlres < 0) */
640
641   /* Set the multicast flag on the interface */
642   memset(&ifreq, 0, sizeof(ifreq));
643   strncpy(ifreq.ifr_name, EtherTunTapIfName, IFNAMSIZ - 1);
644   ifreq.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
645
646   ioctlres = ioctl(ioctl_s, SIOCGIFFLAGS, &ifreq);
647   if (ioctlres >= 0)
648   {
649     ifreq.ifr_flags |= IFF_MULTICAST;
650     ioctlres = ioctl(ioctl_s, SIOCSIFFLAGS, &ifreq);
651   }
652   if (ioctlres < 0)
653   {
654     /* Any of the two above ioctl() calls failed */
655     olsr_printf(
656       1,
657       "%s: error setting multicast flag on EtherTunTap interface \"%s\": %s\n",
658       PLUGIN_NAME,
659       EtherTunTapIfName,
660       strerror(errno));
661     /* Continue anyway */
662   }
663
664   /* Use ioctl to make the tuntap persistent. Otherwise it will disappear
665    * when this program exits. That is not desirable, since a multicast
666    * daemon (e.g. mrouted) may be using the tuntap interface. */
667   if (ioctl(etfd, TUNSETPERSIST, (void *)&ifreq) < 0)
668   {
669     olsr_printf(
670       1,
671       "%s: error making EtherTunTap interface \"%s\" persistent: %s\n",
672       PLUGIN_NAME,
673       EtherTunTapIfName,
674       strerror(errno));
675     /* Continue anyway */
676   }
677
678   /* Deactivate IP spoof filter for EtherTunTap interface */
679   DeactivateSpoofFilter(EtherTunTapIfName);
680
681   OLSR_PRINTF(9, "%s: opened 1 socket on \"%s\"\n", PLUGIN_NAME_SHORT, EtherTunTapIfName);
682
683   /* Keep the highest-numbered descriptor */
684   if (etfd > HighestSkfd)
685   {
686     HighestSkfd = etfd;
687   }
688
689   /* Add descriptor to input set */
690   FD_SET(etfd, &InputSet);
691
692   /* If the user configured a specific IP address for the BMF network interface,
693    * help the user and advertise the IP address of the BMF network interface
694    * on the OLSR network */
695   if (TunTapIpOverruled != 0)
696   {
697     union olsr_ip_addr temp_net;
698     union olsr_ip_addr temp_netmask;
699
700     temp_net.v4 = htonl(EtherTunTapIp);
701     temp_netmask.v4 = htonl(0xFFFFFFFF);
702     add_local_hna4_entry(&temp_net, &temp_netmask);
703   }
704
705   /* If the BMF network interface has a sensible IP address, it is a good idea
706    * to route all multicast traffic through that interface */
707   if (EtherTunTapIp != ETHERTUNTAPDEFAULTIP)
708   {
709     struct rtentry kernel_route;
710
711     memset(&kernel_route, 0, sizeof(struct rtentry));
712
713     ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET;
714     ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET;
715     ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET;
716
717     /* 224.0.0.0/4 */
718     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = htonl(0xE0000000);
719     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = htonl(0xF0000000);
720
721     kernel_route.rt_metric = 0;
722     kernel_route.rt_flags = RTF_UP;
723
724     kernel_route.rt_dev = EtherTunTapIfName;
725
726     if (ioctl(ioctl_s, SIOCADDRT, &kernel_route) < 0)
727     {
728       olsr_printf(
729         1,
730         "%s: error setting multicast route via EtherTunTap interface \"%s\": %s\n",
731         PLUGIN_NAME,
732         EtherTunTapIfName,
733         strerror(errno));
734       /* Continue anyway */
735     }
736   }
737
738   close(ioctl_s);
739
740   return etfd;
741 }
742
743 #if 0
744 /* -------------------------------------------------------------------------
745  * Function   : IsNullMacAddress
746  * Description: Checks if a MAC address is all-zeroes
747  * Input      : mac - address to check
748  * Output     : none
749  * Return     : true (1) or false (0)
750  * Data Used  : none
751  * ------------------------------------------------------------------------- */
752 static int IsNullMacAddress(char* mac)
753 {
754   int i;
755
756   assert(mac != NULL);
757
758   for (i = 0; i < IFHWADDRLEN; i++)
759   {
760     if (mac[i] != 0) return 0;
761   }
762   return 1;
763 }
764 #endif
765
766 /* -------------------------------------------------------------------------
767  * Function   : CreateInterface
768  * Description: Create a new TBmfInterface object and adds it to the global
769  *              BmfInterfaces list
770  * Input      : ifName - name of the network interface (e.g. "eth0")
771  *            : olsrIntf - OLSR interface object of the network interface, or
772  *                NULL if the network interface is not OLSR-enabled
773  * Output     : none
774  * Return     : the number of opened sockets
775  * Data Used  : none
776  * ------------------------------------------------------------------------- */
777 static int CreateInterface(
778   const char* ifName,
779   struct interface* olsrIntf)
780 {
781   int capturingSkfd = -1;
782   int encapsulatingSkfd = -1;
783   int ioctlSkfd;
784   struct ifreq ifr;
785   int nOpened = 0;
786   struct TBmfInterface* newIf = malloc(sizeof(struct TBmfInterface));
787
788   assert(ifName != NULL);
789
790   if (newIf == NULL)
791   {
792     return 0;
793   }
794
795   if (olsrIntf != NULL)
796   {
797     /* On OLSR interfaces, create socket for encapsulating and forwarding 
798      * multicast packets */
799     encapsulatingSkfd = CreateEncapsulateSocket(ifName);
800     if (encapsulatingSkfd < 0)
801     {
802       free(newIf);
803       return 0;
804     }
805     nOpened++;
806   }
807
808   /* Create socket for capturing and sending of multicast packets on
809    * non-OLSR interfaces, and on OLSR-interfaces if configured. */
810   if ((olsrIntf == NULL) || (CapturePacketsOnOlsrInterfaces != 0))
811   {
812     capturingSkfd = CreateCaptureSocket(ifName);
813     if (capturingSkfd < 0)
814     {
815       close(encapsulatingSkfd);
816       free(newIf);
817       return 0;
818     }
819
820     nOpened++;
821   }
822
823   /* For ioctl operations on the network interface, use either capturingSkfd
824    * or encapsulatingSkfd, whichever is available */
825   ioctlSkfd = (capturingSkfd >= 0) ? capturingSkfd : encapsulatingSkfd;
826
827   /* Retrieve the MAC address of the interface. */
828   memset(&ifr, 0, sizeof(struct ifreq));
829   strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
830   ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
831   if (ioctl(ioctlSkfd, SIOCGIFHWADDR, &ifr) < 0)
832   {
833     olsr_printf(
834       1,
835       "%s: ioctl(SIOCGIFHWADDR) error for interface \"%s\": %s\n",
836       PLUGIN_NAME,
837       ifName,
838       strerror(errno));
839     close(capturingSkfd);
840     close(encapsulatingSkfd);
841     free(newIf);
842     return 0;
843   }
844
845   /* If null-interface, cancel the whole creation and return NULL */
846   /* -- Not needed, all goes well with interfaces that have a
847    * null-address, such as ppp interfaces. */
848   /*
849   if (IsNullMacAddress(ifr.ifr_hwaddr.sa_data))
850   {
851     close(capturingSkfd);
852     close(encapsulatingSkfd);
853     free(newIf);
854     return 0;
855   }
856   */
857
858   /* Copy data into TBmfInterface object */
859   newIf->capturingSkfd = capturingSkfd;
860   newIf->encapsulatingSkfd = encapsulatingSkfd;
861   memcpy(newIf->macAddr, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
862   memcpy(newIf->ifName, ifName, IFNAMSIZ);
863   newIf->olsrIntf = olsrIntf;
864   if (olsrIntf != NULL)
865   {
866     /* For an OLSR-interface, copy the interface address and broadcast
867      * address from the OLSR interface object */
868     newIf->intAddr = olsrIntf->int_addr;
869     newIf->broadAddr = olsrIntf->int_broadaddr;
870   }
871   else
872   {
873     /* For a non-OLSR interface, retrieve the IP address ourselves */
874     memset(&ifr, 0, sizeof(struct ifreq));
875     strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
876     ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
877     if (ioctl(ioctlSkfd, SIOCGIFADDR, &ifr) < 0) 
878     {
879       olsr_printf(
880         1,
881         "%s: ioctl(SIOCGIFADDR) error for interface \"%s\": %s\n",
882         PLUGIN_NAME,
883         ifName,
884         strerror(errno));
885
886       ((struct sockaddr_in*)&newIf->intAddr)->sin_addr.s_addr = inet_addr("0.0.0.0");
887           }
888           else
889           {
890       newIf->intAddr = ifr.ifr_addr;
891     }
892
893     /* For a non-OLSR interface, retrieve the IP broadcast address ourselves */
894     memset(&ifr, 0, sizeof(struct ifreq));
895     strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
896     ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
897     if (ioctl(ioctlSkfd, SIOCGIFBRDADDR, &ifr) < 0) 
898     {
899       olsr_printf(
900         1,
901         "%s: ioctl(SIOCGIFBRDADDR) error for interface \"%s\": %s\n",
902         PLUGIN_NAME,
903         ifName,
904         strerror(errno));
905
906       ((struct sockaddr_in*)&newIf->broadAddr)->sin_addr.s_addr = inet_addr("0.0.0.0");
907           }
908           else
909           {
910       newIf->broadAddr = ifr.ifr_broadaddr;
911     }
912   }
913
914   /* Initialize fragment history table */
915   memset(&newIf->fragmentHistory, 0, sizeof(newIf->fragmentHistory));
916   newIf->nextFragmentHistoryEntry = 0;
917
918   /* Add new TBmfInterface object to global list */
919   newIf->next = BmfInterfaces;
920   BmfInterfaces = newIf;
921
922   OLSR_PRINTF(
923     9,
924     "%s: opened %d socket%s on %s interface \"%s\"\n",
925     PLUGIN_NAME_SHORT,
926     nOpened,
927     nOpened == 1 ? "" : "s",
928     olsrIntf != NULL ? "OLSR" : "non-OLSR",
929     ifName);
930
931   return nOpened;
932 }
933
934 /* -------------------------------------------------------------------------
935  * Function   : CreateBmfNetworkInterfaces
936  * Description: Create a list of TBmfInterface objects, one for each network
937  *              interface on which BMF runs
938  * Input      : skipThisIntf - network interface to skip, if seen
939  * Output     : none
940  * Return     : fail (-1) or success (0)
941  * Data Used  : none
942  * ------------------------------------------------------------------------- */
943 int CreateBmfNetworkInterfaces(struct interface* skipThisIntf)
944 {
945   int skfd;
946   struct ifconf ifc;
947   int numreqs = 30;
948   struct ifreq* ifr;
949   int n;
950   int nOpenedSockets = 0;
951
952   /* Clear input descriptor set */
953   FD_ZERO(&InputSet);
954
955   skfd = socket(PF_INET, SOCK_DGRAM, 0);
956   if (skfd < 0)
957   {
958     olsr_printf(
959       1,
960       "%s: no inet socket available to retrieve interface list: %s\n",
961       PLUGIN_NAME,
962       strerror(errno));
963     return -1;
964   }
965
966   /* Retrieve the network interface configuration list */
967   ifc.ifc_buf = NULL;
968   for (;;)
969   {
970     ifc.ifc_len = sizeof(struct ifreq) * numreqs;
971     ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
972
973     if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
974     {
975       olsr_printf(1, "%s: ioctl(SIOCGIFCONF) error: %s\n", PLUGIN_NAME, strerror(errno));
976
977       close(skfd);
978       free(ifc.ifc_buf);
979       return -1;
980     }
981     if ((unsigned)ifc.ifc_len == sizeof(struct ifreq) * numreqs)
982     {
983       /* Assume it overflowed; double the space and try again */
984       numreqs *= 2;
985       assert(numreqs < 1024);
986       continue; /* for (;;) */
987     }
988     break; /* for (;;) */
989   } /* for (;;) */
990
991   close(skfd);
992
993   /* For each item in the interface configuration list... */
994   ifr = ifc.ifc_req;
995   for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++)
996   {
997     struct interface* olsrIntf;
998
999     /* ...find the OLSR interface structure, if any */
1000     union olsr_ip_addr ipAddr;
1001     COPY_IP(&ipAddr, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr.s_addr);
1002     olsrIntf = if_ifwithaddr(&ipAddr);
1003
1004     if (skipThisIntf != NULL && olsrIntf == skipThisIntf)
1005     {
1006       continue; /* for (n = ...) */
1007     }
1008
1009     if (olsrIntf == NULL && ! IsNonOlsrBmfIf(ifr->ifr_name))
1010     {
1011       /* Interface is neither OLSR interface, nor specified as non-OLSR BMF
1012        * interface in the BMF plugin parameter list */
1013       continue; /* for (n = ...) */
1014     }
1015
1016     nOpenedSockets += CreateInterface(ifr->ifr_name, olsrIntf);
1017
1018   } /* for (n = ...) */
1019
1020   free(ifc.ifc_buf);
1021   
1022   /* Create the BMF network interface */
1023   EtherTunTapFd = CreateLocalEtherTunTap();
1024   if (EtherTunTapFd >= 0)
1025   {
1026     nOpenedSockets++;
1027   }
1028
1029   if (BmfInterfaces == NULL)
1030   {
1031     olsr_printf(1, "%s: could not initialize any network interface\n", PLUGIN_NAME);
1032   }
1033   else
1034   {
1035     olsr_printf(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpenedSockets);
1036   }
1037   return 0;
1038 }
1039
1040 /* -------------------------------------------------------------------------
1041  * Function   : AddInterface
1042  * Description: Add an OLSR-enabled network interface to the list of BMF-enabled
1043  *              network interfaces
1044  * Input      : newIntf - network interface to add
1045  * Output     : none
1046  * Return     : none
1047  * Data Used  : none
1048  * ------------------------------------------------------------------------- */
1049 void AddInterface(struct interface* newIntf)
1050 {
1051   int nOpened;
1052
1053   assert(newIntf != NULL);
1054
1055   nOpened = CreateInterface(newIntf->int_name, newIntf);
1056
1057   olsr_printf(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpened);
1058 }
1059
1060 /* -------------------------------------------------------------------------
1061  * Function   : CloseBmfNetworkInterfaces
1062  * Description: Closes every socket on each network interface used by BMF
1063  * Input      : newIntf - network interface to add
1064  * Output     : none
1065  * Return     : none
1066  * Data Used  : none
1067  * Notes      : Closes
1068  *              - the local EtherTunTap interface (e.g. "tun0" or "tap0")
1069  *              - for each BMF-enabled interface, the socket used for
1070  *                capturing multicast packets
1071  *              - for each OLSR-enabled interface, the socket used for
1072  *                encapsulating packets
1073  *              Also restores the network state to the situation before BMF
1074  *              was started.
1075  * ------------------------------------------------------------------------- */
1076
1077 void CloseBmfNetworkInterfaces()
1078 {
1079   int nClosed = 0;
1080   
1081   /* Close all opened sockets */
1082   struct TBmfInterface* nextBmfIf = BmfInterfaces;
1083   while (nextBmfIf != NULL)
1084   {
1085     struct TBmfInterface* bmfIf = nextBmfIf;
1086     nextBmfIf = bmfIf->next;
1087
1088     if (bmfIf->capturingSkfd >= 0)
1089     {
1090       close(bmfIf->capturingSkfd);
1091       nClosed++;
1092     }
1093     if (bmfIf->encapsulatingSkfd >= 0) 
1094     {
1095       close(bmfIf->encapsulatingSkfd);
1096       nClosed++;
1097     }
1098
1099     OLSR_PRINTF(
1100       9,
1101       "%s: closed %s interface \"%s\"\n", 
1102       PLUGIN_NAME_SHORT,
1103       bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR",
1104       bmfIf->ifName);
1105
1106     free(bmfIf);
1107   }
1108   
1109   if (EtherTunTapFd >= 0)
1110   {
1111     /* Restore IP spoof filter for EtherTunTap interface */
1112     RestoreSpoofFilter(EtherTunTapIfName);
1113
1114     close(EtherTunTapFd);
1115     nClosed++;
1116
1117     OLSR_PRINTF(9, "%s: closed \"%s\"\n", PLUGIN_NAME_SHORT, EtherTunTapIfName);
1118   }
1119
1120   BmfInterfaces = NULL;
1121
1122   olsr_printf(1, "%s: closed %d sockets\n", PLUGIN_NAME, nClosed);
1123
1124   /* If there is a multicast route, delete it */
1125   if (EtherTunTapIp != ETHERTUNTAPDEFAULTIP)
1126   {
1127     struct rtentry kernel_route;
1128
1129     memset(&kernel_route, 0, sizeof(struct rtentry));
1130
1131     ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET;
1132     ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET;
1133     ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET;
1134
1135     /* 224.0.0.0/4 */
1136     ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = htonl(0xE0000000);
1137     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = htonl(0xF0000000);
1138
1139     kernel_route.rt_metric = 0;
1140     kernel_route.rt_flags = RTF_UP;
1141
1142     kernel_route.rt_dev = EtherTunTapIfName;
1143
1144     if (ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) < 0)
1145     {
1146       olsr_printf(
1147         1,
1148         "%s: error deleting multicast route via EtherTunTap interface \"%s\": %s\n",
1149         PLUGIN_NAME,
1150         EtherTunTapIfName,
1151         strerror(errno));
1152       /* Continue anyway */
1153     }
1154   }
1155 }
1156
1157 #define MAX_NON_OLSR_IFS 32
1158 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
1159 static int nNonOlsrIfs = 0;
1160
1161 /* -------------------------------------------------------------------------
1162  * Function   : AddNonOlsrBmfIf
1163  * Description: Add an non-OLSR enabled network interface to the list of BMF-enabled
1164  *              network interfaces
1165  * Input      : ifName - network interface (e.g. "eth0")
1166  * Output     : none
1167  * Return     : fail (0) or success (1)
1168  * Data Used  : none
1169  * ------------------------------------------------------------------------- */
1170 int AddNonOlsrBmfIf(const char* ifName)
1171 {
1172   assert(ifName != NULL);
1173
1174   if (nNonOlsrIfs >= MAX_NON_OLSR_IFS)
1175   {
1176     olsr_printf(
1177       1,
1178       "%s: too many non-OLSR interfaces specified, maximum is %d\n",
1179       PLUGIN_NAME,
1180       MAX_NON_OLSR_IFS);
1181     return 0;
1182   }
1183
1184   strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ - 1);
1185   NonOlsrIfNames[nNonOlsrIfs][IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
1186   nNonOlsrIfs++;
1187   return 1;
1188 }
1189
1190 /* -------------------------------------------------------------------------
1191  * Function   : IsNonOlsrBmfIf
1192  * Description: Checks if a network interface is OLSR-enabled
1193  * Input      : ifName - network interface (e.g. "eth0")
1194  * Output     : none
1195  * Return     : true (1) or false (0)
1196  * Data Used  : none
1197  * ------------------------------------------------------------------------- */
1198 int IsNonOlsrBmfIf(const char* ifName)
1199 {
1200   int i;
1201
1202   assert(ifName != NULL);
1203
1204   for (i = 0; i < nNonOlsrIfs; i++)
1205   {
1206     if (strncmp(NonOlsrIfNames[i], ifName, IFNAMSIZ) == 0) return 1;
1207   }
1208   return 0;
1209 }
1210
1211 /* -------------------------------------------------------------------------
1212  * Function   : CheckAndUpdateLocalBroadcast
1213  * Description: For an IP packet, check if the destination address is not a
1214  *              multicast address. If it is not, the packet is assumed to be
1215  *              a local broadcast packet. Update the destination address to
1216  *              match the passed network interface.
1217  * Input      : buffer - the ethernet-IP packet
1218  *              broadAddr - the broadcast address to fill in
1219  * Output     : none
1220  * Return     : none
1221  * Data Used  : none
1222  * Notes      : See also RFC1141
1223  * ------------------------------------------------------------------------- */
1224 void CheckAndUpdateLocalBroadcast(unsigned char* buffer, struct sockaddr* broadAddr)
1225 {
1226   struct iphdr* iph;
1227   union olsr_ip_addr destIp;
1228
1229   assert(buffer != NULL && broadAddr != NULL);
1230
1231   iph = (struct iphdr*) (buffer + IP_HDR_OFFSET);
1232   COPY_IP(&destIp, &iph->daddr);
1233   if (! IsMulticast(&destIp))
1234   {
1235     u_int32_t origDaddr, newDaddr;
1236     struct sockaddr_in* sin;
1237     u_int32_t check;
1238
1239     /* Cast down to correct sockaddr subtype */
1240     sin = (struct sockaddr_in*)broadAddr;
1241     
1242     origDaddr = ntohl(iph->daddr);
1243
1244     iph->daddr = sin->sin_addr.s_addr;
1245     newDaddr = ntohl(iph->daddr);
1246
1247     /* Re-calculate IP header checksum for new destination */
1248     check = ntohs(iph->check);
1249
1250     check = ~ (~ check - ((origDaddr >> 16) & 0xFFFF) + ((newDaddr >> 16) & 0xFFFF));
1251     check = ~ (~ check - (origDaddr & 0xFFFF) + (newDaddr & 0xFFFF));
1252
1253     /* Add carry */
1254     check = check + (check >> 16);
1255
1256     iph->check = htons(check);
1257
1258     if (iph->protocol == SOL_UDP)
1259     {
1260       /* Re-calculate UDP/IP checksum for new destination */
1261
1262       int ipHeaderLen = GetIpHeaderLength(buffer);
1263       struct udphdr* udph = (struct udphdr*) (buffer + IP_HDR_OFFSET + ipHeaderLen);
1264
1265       /* RFC 1624, Eq. 3: HC' = ~(~HC - m + m') */
1266
1267       check = ntohs(udph->check);
1268
1269       check = ~ (~ check - ((origDaddr >> 16) & 0xFFFF) + ((newDaddr >> 16) & 0xFFFF));
1270       check = ~ (~ check - (origDaddr & 0xFFFF) + (newDaddr & 0xFFFF));
1271
1272       /* Add carry */
1273       check = check + (check >> 16);
1274
1275       udph->check = htons(check);
1276      }
1277   }
1278 }
1279