2 * The olsr.org Optimized Link-State Routing daemon(olsrd)
3 * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
16 * * Neither the name of olsr.org, olsrd nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
33 * Visit http://www.olsr.org for more information.
35 * If you find this software useful feel free to make a donation
36 * to the project. For more information see the website or contact
37 * the copyright holders.
42 #include "NetworkInterfaces.h"
45 #include <stddef.h> /* NULL */
46 #include <syslog.h> /* syslog() */
47 #include <string.h> /* strerror(), strchr(), strcmp() */
48 #include <errno.h> /* errno */
49 #include <unistd.h> /* close() */
50 #include <sys/ioctl.h> /* ioctl() */
51 #include <fcntl.h> /* fcntl() */
52 #include <assert.h> /* assert() */
53 #include <net/if.h> /* socket(), ifreq, if_indextoname(), if_nametoindex() */
54 #include <netinet/in.h> /* htons() */
56 #include <linux/if_ether.h> /* ETH_P_IP */
57 #include <linux/if_packet.h> /* packet_mreq, PACKET_MR_PROMISC, PACKET_ADD_MEMBERSHIP */
58 #include <linux/if_tun.h> /* IFF_TAP */
60 #include <netinet/ip.h> /* struct ip */
61 #include <netinet/udp.h> /* SOL_UDP */
62 #include <stdlib.h> /* atoi, malloc */
65 #include "olsr.h" /* OLSR_PRINTF() */
67 #include "defs.h" /* olsr_cnf */
68 #include "link_set.h" /* get_link_set() */
69 #include "tc_set.h" /* olsr_lookup_tc_entry(), olsr_lookup_tc_edge() */
70 #include "net_olsr.h" /* ipequal */
71 #include "lq_plugin.h"
72 //#include "olsr_ip_prefix_list.h"
75 #include "Packet.h" /* IFHWADDRLEN */
76 #include "mdns.h" /* PLUGIN_NAME, MainAddressOf() */
77 #include "Address.h" /* IsMulticast() */
81 /* List of network interface objects used by BMF plugin */
82 struct TBmfInterface *BmfInterfaces = NULL;
83 struct TBmfInterface *LastBmfInterface = NULL;
85 /* Highest-numbered open socket file descriptor. To be used as first
86 * parameter in calls to select(...). */
89 /* Set of socket file descriptors */
93 /* -------------------------------------------------------------------------
94 * Function : CreateCaptureSocket
95 * Description: Create socket for promiscuously capturing multicast IP traffic
96 * Input : ifname - network interface (e.g. "eth0")
98 * Return : the socket descriptor ( >= 0), or -1 if an error occurred
100 * Notes : The socket is a cooked IP packet socket, bound to the specified
102 * ------------------------------------------------------------------------- */
104 CreateCaptureSocket(const char *ifName)
106 int ifIndex = if_nametoindex(ifName);
107 struct packet_mreq mreq;
109 struct sockaddr_ll bindTo;
111 /* Open cooked IP packet socket */
112 if (olsr_cnf->ip_version == AF_INET) {
113 skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
115 skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
118 BmfPError("socket(PF_PACKET) error");
122 /* Set interface to promiscuous mode */
123 memset(&mreq, 0, sizeof(struct packet_mreq));
124 mreq.mr_ifindex = ifIndex;
125 mreq.mr_type = PACKET_MR_PROMISC;
126 if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
127 BmfPError("setsockopt(PACKET_MR_PROMISC) error");
132 /* Get hardware (MAC) address */
133 memset(&req, 0, sizeof(struct ifreq));
134 strncpy(req.ifr_name, ifName, IFNAMSIZ - 1);
135 req.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
136 if (ioctl(skfd, SIOCGIFHWADDR, &req) < 0) {
137 BmfPError("error retrieving MAC address");
142 /* Bind the socket to the specified interface */
143 memset(&bindTo, 0, sizeof(bindTo));
144 bindTo.sll_family = AF_PACKET;
145 if (olsr_cnf->ip_version == AF_INET) {
146 bindTo.sll_protocol = htons(ETH_P_IP);
148 bindTo.sll_protocol = htons(ETH_P_IPV6);
150 bindTo.sll_ifindex = ifIndex;
151 memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
152 bindTo.sll_halen = IFHWADDRLEN;
154 if (bind(skfd, (struct sockaddr *)&bindTo, sizeof(bindTo)) < 0) {
155 BmfPError("bind() error");
160 /* Set socket to blocking operation */
161 if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
162 BmfPError("fcntl() error");
166 //AddDescriptorToInputSet(skfd);
167 add_olsr_socket(skfd, &DoMDNS,NULL, NULL, SP_PR_READ);
170 } /* CreateCaptureSocket */
172 /* -------------------------------------------------------------------------
173 * Function : CreateInterface
174 * Description: Create a new TBmfInterface object and adds it to the global
176 * Input : ifName - name of the network interface (e.g. "eth0")
177 * : olsrIntf - OLSR interface object of the network interface, or
178 * NULL if the network interface is not OLSR-enabled
180 * Return : the number of opened sockets
181 * Data Used : BmfInterfaces, LastBmfInterface
182 * ------------------------------------------------------------------------- */
184 //FOR MDNS IS ALWAYS CALLED WITH NULL AS SECOND ARG
187 CreateInterface(const char *ifName, struct interface *olsrIntf)
189 int capturingSkfd = -1;
190 int encapsulatingSkfd = -1;
191 int listeningSkfd = -1;
195 struct TBmfInterface *newIf = olsr_malloc(sizeof(struct TBmfInterface), "TBMFInterface (mdns)");
197 assert(ifName != NULL);
202 //TODO: assert interface is not talking OLSR
205 /* Create socket for capturing and sending of multicast packets on
206 * non-OLSR interfaces, and on OLSR-interfaces if configured. */
207 if ((olsrIntf == NULL)) {
208 capturingSkfd = CreateCaptureSocket(ifName);
209 if (capturingSkfd < 0) {
210 close(encapsulatingSkfd);
218 /* For ioctl operations on the network interface, use either capturingSkfd
219 * or encapsulatingSkfd, whichever is available */
220 ioctlSkfd = (capturingSkfd >= 0) ? capturingSkfd : encapsulatingSkfd;
222 /* Retrieve the MAC address of the interface. */
223 memset(&ifr, 0, sizeof(struct ifreq));
224 strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
225 ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
226 if (ioctl(ioctlSkfd, SIOCGIFHWADDR, &ifr) < 0) {
227 BmfPError("ioctl(SIOCGIFHWADDR) error for interface \"%s\"", ifName);
228 close(capturingSkfd);
229 close(encapsulatingSkfd);
234 /* Copy data into TBmfInterface object */
235 newIf->capturingSkfd = capturingSkfd;
236 newIf->encapsulatingSkfd = encapsulatingSkfd;
237 newIf->listeningSkfd = listeningSkfd;
238 memcpy(newIf->macAddr, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
239 memcpy(newIf->ifName, ifName, IFNAMSIZ);
240 newIf->olsrIntf = olsrIntf;
241 if (olsrIntf != NULL) {
242 /* For an OLSR-interface, copy the interface address and broadcast
243 * address from the OLSR interface object. Downcast to correct sockaddr
245 newIf->intAddr.v4 = olsrIntf->int_addr.sin_addr;
246 newIf->broadAddr.v4 = olsrIntf->int_broadaddr.sin_addr;
248 /* For a non-OLSR interface, retrieve the IP address ourselves */
249 memset(&ifr, 0, sizeof(struct ifreq));
250 strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
251 ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
252 if (ioctl(ioctlSkfd, SIOCGIFADDR, &ifr) < 0) {
253 BmfPError("ioctl(SIOCGIFADDR) error for interface \"%s\"", ifName);
255 newIf->intAddr.v4.s_addr = inet_addr("0.0.0.0");
257 /* Downcast to correct sockaddr subtype */
258 newIf->intAddr.v4 = ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&ifr.ifr_addr)->sin_addr;
261 /* For a non-OLSR interface, retrieve the IP broadcast address ourselves */
262 memset(&ifr, 0, sizeof(struct ifreq));
263 strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
264 ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
265 if (ioctl(ioctlSkfd, SIOCGIFBRDADDR, &ifr) < 0) {
266 BmfPError("ioctl(SIOCGIFBRDADDR) error for interface \"%s\"", ifName);
268 newIf->broadAddr.v4.s_addr = inet_addr("0.0.0.0");
270 /* Downcast to correct sockaddr subtype */
271 newIf->broadAddr.v4 = ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&ifr.ifr_broadaddr)->sin_addr;
275 /* Initialize fragment history table */
276 //memset(&newIf->fragmentHistory, 0, sizeof(newIf->fragmentHistory));
277 //newIf->nextFragmentHistoryEntry = 0;
280 //newIf->nBmfPacketsRx = 0;
281 //newIf->nBmfPacketsRxDup = 0;
282 //newIf->nBmfPacketsTx = 0;
284 /* Add new TBmfInterface object to global list. OLSR interfaces are
285 * added at the front of the list, non-OLSR interfaces at the back. */
286 if (BmfInterfaces == NULL) {
287 /* First TBmfInterface object in list */
288 BmfInterfaces = newIf;
289 LastBmfInterface = newIf;
290 } else if (olsrIntf != NULL) {
291 /* Add new TBmfInterface object at front of list */
292 newIf->next = BmfInterfaces;
293 BmfInterfaces = newIf;
295 /* Add new TBmfInterface object at back of list */
297 LastBmfInterface->next = newIf;
298 LastBmfInterface = newIf;
303 // "%s: opened %d socket%s on %s interface \"%s\"\n",
304 // PLUGIN_NAME_SHORT,
306 // nOpened == 1 ? "" : "s",
307 // olsrIntf != NULL ? "OLSR" : "non-OLSR",
311 } /* CreateInterface */
313 /* -------------------------------------------------------------------------
314 * Function : CreateBmfNetworkInterfaces
315 * Description: Create a list of TBmfInterface objects, one for each network
316 * interface on which BMF runs
317 * Input : skipThisIntf - network interface to skip, if seen
319 * Return : fail (-1) or success (0)
321 * ------------------------------------------------------------------------- */
323 CreateBmfNetworkInterfaces(struct interface *skipThisIntf)
330 int nOpenedSockets = 0;
332 /* Clear input descriptor set */
335 skfd = socket(PF_INET, SOCK_DGRAM, 0);
337 BmfPError("no inet socket available to retrieve interface list");
341 /* Retrieve the network interface configuration list */
344 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
345 ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
347 if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
348 BmfPError("ioctl(SIOCGIFCONF) error");
354 if ((unsigned)ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
355 /* Assume it overflowed; double the space and try again */
357 assert(numreqs < 1024);
358 continue; /* for (;;) */
360 break; /* for (;;) */
365 /* For each item in the interface configuration list... */
367 for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++) {
368 struct interface *olsrIntf;
369 union olsr_ip_addr ipAddr;
371 /* Skip the BMF network interface itself */
372 //if (strncmp(ifr->ifr_name, EtherTunTapIfName, IFNAMSIZ) == 0)
374 // continue; /* for (n = ...) */
377 /* ...find the OLSR interface structure, if any */
378 ipAddr.v4 = ((struct sockaddr_in *)(ARM_NOWARN_ALIGN)&ifr->ifr_addr)->sin_addr;
379 olsrIntf = if_ifwithaddr(&ipAddr);
381 if (skipThisIntf != NULL && olsrIntf == skipThisIntf) {
382 continue; /* for (n = ...) */
385 if (olsrIntf == NULL && !IsNonOlsrBmfIf(ifr->ifr_name)) {
386 /* Interface is neither OLSR interface, nor specified as non-OLSR BMF
387 * interface in the BMF plugin parameter list */
388 continue; /* for (n = ...) */
391 if (!IsNonOlsrBmfIf(ifr->ifr_name)) {
392 //If the interface is not specified in the configuration file then go ahead
393 continue; /* for (n = ...) */
395 //TODO: asser if->ifr_name is not talking OLSR
396 //nOpenedSockets += CreateInterface(ifr->ifr_name, olsrIntf);
397 nOpenedSockets += CreateInterface(ifr->ifr_name, NULL);
399 } /* for (n = ...) */
403 if (BmfInterfaces == NULL) {
404 //OLSR_PRINTF(1, "%s: could not initialize any network interface\n", PLUGIN_NAME);
406 //OLSR_PRINTF(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpenedSockets);
409 } /* CreateBmfNetworkInterfaces */
411 /* -------------------------------------------------------------------------
412 * Function : AddInterface
413 * Description: Add an OLSR-enabled network interface to the list of BMF-enabled
415 * Input : newIntf - network interface to add
419 * ------------------------------------------------------------------------- */
421 AddInterface(struct interface *newIntf)
425 assert(newIntf != NULL);
427 nOpened = CreateInterface(newIntf->int_name, newIntf);
429 //OLSR_PRINTF(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpened);
432 /* -------------------------------------------------------------------------
433 * Function : CloseBmfNetworkInterfaces
434 * Description: Closes every socket on each network interface used by BMF
440 * - the local EtherTunTap interface (e.g. "tun0" or "tap0")
441 * - for each BMF-enabled interface, the socket used for
442 * capturing multicast packets
443 * - for each OLSR-enabled interface, the socket used for
444 * encapsulating packets
445 * Also restores the network state to the situation before BMF
447 * ------------------------------------------------------------------------- */
449 CloseBmfNetworkInterfaces(void)
452 u_int32_t totalOlsrBmfPacketsRx = 0;
453 u_int32_t totalOlsrBmfPacketsRxDup = 0;
454 u_int32_t totalOlsrBmfPacketsTx = 0;
455 u_int32_t totalNonOlsrBmfPacketsRx = 0;
456 u_int32_t totalNonOlsrBmfPacketsRxDup = 0;
457 u_int32_t totalNonOlsrBmfPacketsTx = 0;
459 /* Close all opened sockets */
460 struct TBmfInterface *nextBmfIf = BmfInterfaces;
461 while (nextBmfIf != NULL) {
462 struct TBmfInterface *bmfIf = nextBmfIf;
463 nextBmfIf = bmfIf->next;
465 if (bmfIf->capturingSkfd >= 0) {
466 close(bmfIf->capturingSkfd);
469 if (bmfIf->encapsulatingSkfd >= 0) {
470 close(bmfIf->encapsulatingSkfd);
475 // "%s: %s interface \"%s\": RX pkts %u (%u dups); TX pkts %u\n",
476 // PLUGIN_NAME_SHORT,
477 // bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR",
479 // bmfIf->nBmfPacketsRx,
480 // bmfIf->nBmfPacketsRxDup,
481 // bmfIf->nBmfPacketsTx);
485 // "%s: closed %s interface \"%s\"\n",
486 // PLUGIN_NAME_SHORT,
487 // bmfIf->olsrIntf != NULL ? "OLSR" : "non-OLSR",
491 if (bmfIf->olsrIntf != NULL) {
492 totalOlsrBmfPacketsRx += bmfIf->nBmfPacketsRx;
493 totalOlsrBmfPacketsRxDup += bmfIf->nBmfPacketsRxDup;
494 totalOlsrBmfPacketsTx += bmfIf->nBmfPacketsTx;
496 totalNonOlsrBmfPacketsRx += bmfIf->nBmfPacketsRx;
497 totalNonOlsrBmfPacketsRxDup += bmfIf->nBmfPacketsRxDup;
498 totalNonOlsrBmfPacketsTx += bmfIf->nBmfPacketsTx;
504 BmfInterfaces = NULL;
506 //OLSR_PRINTF(1, "%s: closed %d sockets\n", PLUGIN_NAME_SHORT, nClosed);
508 } /* CloseBmfNetworkInterfaces */
510 #define MAX_NON_OLSR_IFS 32
511 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
512 static int nNonOlsrIfs = 0;
513 /* -------------------------------------------------------------------------
514 * Function : AddNonOlsrBmfIf
515 * Description: Add an non-OLSR enabled network interface to the list of BMF-enabled
517 * Input : ifName - network interface (e.g. "eth0")
521 * Return : success (0) or fail (1)
522 * Data Used : NonOlsrIfNames
523 * ------------------------------------------------------------------------- */
525 AddNonOlsrBmfIf(const char *ifName, void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
527 assert(ifName != NULL);
529 if (nNonOlsrIfs >= MAX_NON_OLSR_IFS) {
532 // "%s: too many non-OLSR interfaces specified, maximum is %d\n",
534 // MAX_NON_OLSR_IFS);
538 strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ - 1);
539 NonOlsrIfNames[nNonOlsrIfs][IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
542 } /* AddNonOlsrBmfIf */
546 set_MDNS_TTL(const char *MDNS_TTL, void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
548 assert(MDNS_TTL!= NULL);
549 my_MDNS_TTL = atoi(MDNS_TTL);
552 /* -------------------------------------------------------------------------
553 * Function : IsNonOlsrBmfIf
554 * Description: Checks if a network interface is OLSR-enabled
555 * Input : ifName - network interface (e.g. "eth0")
557 * Return : true (1) or false (0)
558 * Data Used : NonOlsrIfNames
559 * ------------------------------------------------------------------------- */
561 IsNonOlsrBmfIf(const char *ifName)
565 assert(ifName != NULL);
567 for (i = 0; i < nNonOlsrIfs; i++) {
568 if (strncmp(NonOlsrIfNames[i], ifName, IFNAMSIZ) == 0)
572 } /* IsNonOlsrBmfIf */