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() */
55 #include <linux/if_ether.h> /* ETH_P_IP */
56 #include <linux/if_packet.h> /* packet_mreq, PACKET_MR_PROMISC, PACKET_ADD_MEMBERSHIP */
57 #include <linux/if_tun.h> /* IFF_TAP */
58 #include <netinet/ip.h> /* struct ip */
59 #include <netinet/udp.h> /* SOL_UDP */
60 #include <stdlib.h> /* atoi, malloc */
63 #include "olsr.h" /* OLSR_PRINTF() */
65 #include "defs.h" /* olsr_cnf */
66 #include "link_set.h" /* get_link_set() */
67 #include "tc_set.h" /* olsr_lookup_tc_entry(), olsr_lookup_tc_edge() */
68 #include "net_olsr.h" /* ipequal */
69 #include "lq_plugin.h"
70 //#include "olsr_ip_prefix_list.h"
73 #include "Packet.h" /* IFHWADDRLEN */
74 #include "p2pd.h" /* PLUGIN_NAME, MainAddressOf() */
75 //#include "Address.h" /* IsMulticast() */
78 /* List of network interface objects used by BMF plugin */
79 struct NonOlsrInterface *nonOlsrInterfaces = NULL;
80 struct NonOlsrInterface *lastNonOlsrInterface = NULL;
82 /* -------------------------------------------------------------------------
83 * Function : CreateCaptureSocket
84 * Description: Create socket for promiscuously capturing multicast IP traffic
85 * Input : ifname - network interface (e.g. "eth0")
87 * Return : the socket descriptor ( >= 0), or -1 if an error occurred
89 * Notes : The socket is a cooked IP packet socket, bound to the specified
91 * ------------------------------------------------------------------------- */
93 CreateCaptureSocket(const char *ifName)
95 int ifIndex = if_nametoindex(ifName);
96 struct packet_mreq mreq;
98 struct sockaddr_ll bindTo;
100 /* Open cooked IP packet socket */
101 if (olsr_cnf->ip_version == AF_INET) {
102 skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
104 skfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
107 P2pdPError("socket(PF_PACKET) error");
111 /* Set interface to promiscuous mode */
112 memset(&mreq, 0, sizeof(struct packet_mreq));
113 mreq.mr_ifindex = ifIndex;
114 mreq.mr_type = PACKET_MR_PROMISC;
115 if (setsockopt(skfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
116 P2pdPError("setsockopt(PACKET_MR_PROMISC) error");
121 /* Get hardware (MAC) address */
122 memset(&req, 0, sizeof(struct ifreq));
123 strncpy(req.ifr_name, ifName, IFNAMSIZ - 1);
124 req.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
125 if (ioctl(skfd, SIOCGIFHWADDR, &req) < 0) {
126 P2pdPError("error retrieving MAC address");
131 /* Bind the socket to the specified interface */
132 memset(&bindTo, 0, sizeof(bindTo));
133 bindTo.sll_family = AF_PACKET;
134 if (olsr_cnf->ip_version == AF_INET) {
135 bindTo.sll_protocol = htons(ETH_P_IP);
137 bindTo.sll_protocol = htons(ETH_P_IPV6);
139 bindTo.sll_ifindex = ifIndex;
140 memcpy(bindTo.sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
141 bindTo.sll_halen = IFHWADDRLEN;
143 if (bind(skfd, (struct sockaddr *)&bindTo, sizeof(bindTo)) < 0) {
144 P2pdPError("bind() error");
149 /* Set socket to blocking operation */
150 if (fcntl(skfd, F_SETFL, fcntl(skfd, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
151 P2pdPError("fcntl() error");
155 //AddDescriptorToInputSet(skfd);
156 add_olsr_socket(skfd, (socket_handler_func)&DoP2pd, NULL, NULL, SP_PR_READ);
159 } /* CreateCaptureSocket */
161 /* -------------------------------------------------------------------------
162 * Function : CreateInterface
163 * Description: Create a new NonOlsrInterface object and adds it to the global
164 * nonOlsrInterfaces list
165 * Input : ifName - name of the network interface (e.g. "eth0")
166 * : olsrIntf - OLSR interface object of the network interface, or
167 * NULL if the network interface is not OLSR-enabled
169 * Return : the number of opened sockets
170 * Data Used : nonOlsrInterfaces, lastNonOlsrInterface
171 * ------------------------------------------------------------------------- */
173 //FOR MDNS IS ALWAYS CALLED WITH NULL AS SECOND ARG
176 CreateInterface(const char *ifName, struct interface_olsr *olsrIntf)
178 int capturingSkfd = -1;
179 int encapsulatingSkfd = -1;
180 int listeningSkfd = -1;
184 struct NonOlsrInterface *newIf = malloc(sizeof(struct NonOlsrInterface));
186 assert(ifName != NULL);
191 //TODO: assert interface is not talking OLSR
194 /* Create socket for capturing and sending of multicast packets on
195 * non-OLSR interfaces, and on OLSR-interfaces if configured. */
197 capturingSkfd = CreateCaptureSocket(ifName);
198 if (capturingSkfd < 0) {
206 /* For ioctl operations on the network interface, use either capturingSkfd
207 * or encapsulatingSkfd, whichever is available */
208 ioctlSkfd = (capturingSkfd >= 0) ? capturingSkfd : encapsulatingSkfd;
210 /* Retrieve the MAC address of the interface. */
211 memset(&ifr, 0, sizeof(struct ifreq));
212 strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
213 ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
214 if (ioctl(ioctlSkfd, SIOCGIFHWADDR, &ifr) < 0) {
215 P2pdPError("ioctl(SIOCGIFHWADDR) error for interface \"%s\"", ifName);
216 if (capturingSkfd >= 0) {
217 close(capturingSkfd);
223 /* Copy data into NonOlsrInterface object */
224 newIf->capturingSkfd = capturingSkfd;
225 newIf->encapsulatingSkfd = encapsulatingSkfd;
226 newIf->listeningSkfd = listeningSkfd;
227 memcpy(newIf->macAddr, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
228 memcpy(newIf->ifName, ifName, IFNAMSIZ);
229 newIf->olsrIntf = olsrIntf;
230 if (olsrIntf != NULL) {
231 /* For an OLSR-interface, copy the interface address and broadcast
232 * address from the OLSR interface object. Downcast to correct sockaddr
234 newIf->intAddr.v4 = olsrIntf->int_addr.sin_addr;
235 newIf->broadAddr.v4 = olsrIntf->int_broadaddr.sin_addr;
237 /* For a non-OLSR interface, retrieve the IP address ourselves */
238 memset(&ifr, 0, sizeof(struct ifreq));
239 strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
240 ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
241 if (ioctl(ioctlSkfd, SIOCGIFADDR, &ifr) < 0) {
242 P2pdPError("ioctl(SIOCGIFADDR) error for interface \"%s\"", ifName);
244 newIf->intAddr.v4.s_addr = inet_addr("0.0.0.0");
246 /* Downcast to correct sockaddr subtype */
247 newIf->intAddr.v4 = ((struct sockaddr_in *) ARM_NOWARN_ALIGN(&ifr.ifr_addr))->sin_addr;
250 /* For a non-OLSR interface, retrieve the IP broadcast address ourselves */
251 memset(&ifr, 0, sizeof(struct ifreq));
252 strncpy(ifr.ifr_name, ifName, IFNAMSIZ - 1);
253 ifr.ifr_name[IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
254 if (ioctl(ioctlSkfd, SIOCGIFBRDADDR, &ifr) < 0) {
255 P2pdPError("ioctl(SIOCGIFBRDADDR) error for interface \"%s\"", ifName);
257 newIf->broadAddr.v4.s_addr = inet_addr("0.0.0.0");
259 /* Downcast to correct sockaddr subtype */
260 newIf->broadAddr.v4 = ((struct sockaddr_in *) ARM_NOWARN_ALIGN(&ifr.ifr_broadaddr))->sin_addr;
264 /* Initialize fragment history table */
265 //memset(&newIf->fragmentHistory, 0, sizeof(newIf->fragmentHistory));
266 //newIf->nextFragmentHistoryEntry = 0;
269 //newIf->nNonOlsrPacketsRx = 0;
270 //newIf->nNonOlsrPacketsRxDup = 0;
271 //newIf->nNonOlsrPacketsTx = 0;
273 /* Add new NonOlsrInterface object to global list. OLSR interfaces are
274 * added at the front of the list, non-OLSR interfaces at the back. */
275 if (nonOlsrInterfaces == NULL) {
276 /* First NonOlsrInterface object in list */
278 nonOlsrInterfaces = newIf;
279 lastNonOlsrInterface = newIf;
280 } else if (olsrIntf != NULL) {
281 /* Add new NonOlsrInterface object at front of list */
282 newIf->next = nonOlsrInterfaces;
283 nonOlsrInterfaces = newIf;
285 /* Add new NonOlsrInterface object at back of list */
287 lastNonOlsrInterface->next = newIf;
288 lastNonOlsrInterface = newIf;
293 // "%s: opened %d socket%s on %s interface \"%s\"\n",
294 // PLUGIN_NAME_SHORT,
296 // nOpened == 1 ? "" : "s",
297 // olsrIntf != NULL ? "OLSR" : "non-OLSR",
301 } /* CreateInterface */
303 /* -------------------------------------------------------------------------
304 * Function : CreateNonOlsrNetworkInterfaces
305 * Description: Create a list of NonOlsrInterface objects, one for each network
306 * interface on which BMF runs
307 * Input : skipThisIntf - network interface to skip, if seen
309 * Return : fail (-1) or success (0)
311 * ------------------------------------------------------------------------- */
313 CreateNonOlsrNetworkInterfaces(struct interface_olsr *skipThisIntf)
320 int nOpenedSockets = 0;
322 /* Clear input descriptor set */
325 skfd = socket(PF_INET, SOCK_DGRAM, 0);
327 P2pdPError("no inet socket available to retrieve interface list");
331 /* Retrieve the network interface configuration list */
334 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
335 ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
337 if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
338 P2pdPError("ioctl(SIOCGIFCONF) error");
344 if ((unsigned)ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
345 /* Assume it overflowed; double the space and try again */
347 assert(numreqs < 1024);
348 continue; /* for (;;) */
350 break; /* for (;;) */
355 /* For each item in the interface configuration list... */
357 for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++) {
358 struct interface_olsr *olsrIntf;
359 union olsr_ip_addr ipAddr;
361 /* Skip the BMF network interface itself */
362 //if (strncmp(ifr->ifr_name, EtherTunTapIfName, IFNAMSIZ) == 0)
364 // continue; /* for (n = ...) */
367 /* ...find the OLSR interface structure, if any */
368 ipAddr.v4 = ((struct sockaddr_in *) ARM_NOWARN_ALIGN(&ifr->ifr_addr))->sin_addr;
369 olsrIntf = if_ifwithaddr(&ipAddr);
371 if (skipThisIntf != NULL && olsrIntf == skipThisIntf) {
372 continue; /* for (n = ...) */
375 if (olsrIntf == NULL && !IsNonOlsrIf(ifr->ifr_name)) {
376 /* Interface is neither OLSR interface, nor specified as non-OLSR
377 * interface in the plugin parameter list */
378 continue; /* for (n = ...) */
381 if (!IsNonOlsrIf(ifr->ifr_name)) {
382 //If the interface is not specified in the configuration file then go ahead
383 continue; /* for (n = ...) */
385 //TODO: asser if->ifr_name is not talking OLSR
386 //nOpenedSockets += CreateInterface(ifr->ifr_name, olsrIntf);
387 nOpenedSockets += CreateInterface(ifr->ifr_name, NULL);
389 } /* for (n = ...) */
393 if (nonOlsrInterfaces == NULL) {
394 //OLSR_PRINTF(1, "%s: could not initialize any network interface\n", PLUGIN_NAME);
396 //OLSR_PRINTF(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpenedSockets);
399 } /* CreateNonOlsrNetworkInterfaces */
401 /* -------------------------------------------------------------------------
402 * Function : AddInterface
403 * Description: Add an OLSR-enabled network interface to the list of BMF-enabled
405 * Input : newIntf - network interface to add
409 * ------------------------------------------------------------------------- */
411 AddInterface(struct interface_olsr *newIntf)
415 assert(newIntf != NULL);
417 /* nOpened = */ (void)CreateInterface(newIntf->int_name, newIntf);
419 //OLSR_PRINTF(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpened);
422 /* -------------------------------------------------------------------------
423 * Function : CloseNonOlsrNetworkInterfaces
424 * Description: Closes every socket on each network interface used by BMF
430 * - the local EtherTunTap interface (e.g. "tun0" or "tap0")
431 * - for each BMF-enabled interface, the socket used for
432 * capturing multicast packets
433 * - for each OLSR-enabled interface, the socket used for
434 * encapsulating packets
435 * Also restores the network state to the situation before BMF
437 * ------------------------------------------------------------------------- */
439 CloseNonOlsrNetworkInterfaces(void)
442 u_int32_t totalOlsrPacketsRx = 0;
443 u_int32_t totalOlsrPacketsRxDup = 0;
444 u_int32_t totalOlsrPacketsTx = 0;
445 u_int32_t totalNonOlsrPacketsRx = 0;
446 u_int32_t totalNonOlsrPacketsRxDup = 0;
447 u_int32_t totalNonOlsrPacketsTx = 0;
449 /* Close all opened sockets */
450 struct NonOlsrInterface *nextIf = nonOlsrInterfaces;
451 while (nextIf != NULL) {
452 struct NonOlsrInterface *ifc = nextIf;
455 if (ifc->capturingSkfd >= 0) {
456 close(ifc->capturingSkfd);
459 if (ifc->encapsulatingSkfd >= 0) {
460 close(ifc->encapsulatingSkfd);
465 // "%s: %s interface \"%s\": RX pkts %u (%u dups); TX pkts %u\n",
466 // PLUGIN_NAME_SHORT,
467 // ifc->olsrIntf != NULL ? "OLSR" : "non-OLSR",
470 // ifc->nPacketsRxDup,
475 // "%s: closed %s interface \"%s\"\n",
476 // PLUGIN_NAME_SHORT,
477 // ifc->olsrIntf != NULL ? "OLSR" : "non-OLSR",
481 if (ifc->olsrIntf != NULL) {
482 totalOlsrPacketsRx += ifc->nPacketsRx;
483 totalOlsrPacketsRxDup += ifc->nPacketsRxDup;
484 totalOlsrPacketsTx += ifc->nPacketsTx;
486 totalNonOlsrPacketsRx += ifc->nPacketsRx;
487 totalNonOlsrPacketsRxDup += ifc->nPacketsRxDup;
488 totalNonOlsrPacketsTx += ifc->nPacketsTx;
494 nonOlsrInterfaces = NULL;
496 //OLSR_PRINTF(1, "%s: closed %d sockets\n", PLUGIN_NAME_SHORT, nClosed);
498 } /* CloseNonOlsrNetworkInterfaces */
500 #define MAX_NON_OLSR_IFS 32
501 static char NonOlsrIfNames[MAX_NON_OLSR_IFS][IFNAMSIZ];
502 static int nNonOlsrIfs = 0;
503 /* -------------------------------------------------------------------------
504 * Function : AddNonOlsrIf
505 * Description: Add an non-OLSR enabled network interface to the list of BMF-enabled
507 * Input : ifName - network interface (e.g. "eth0")
511 * Return : success (0) or fail (1)
512 * Data Used : NonOlsrIfNames
513 * ------------------------------------------------------------------------- */
515 AddNonOlsrIf(const char *ifName, void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
517 assert(ifName != NULL);
519 if (nNonOlsrIfs >= MAX_NON_OLSR_IFS) {
522 // "%s: too many non-OLSR interfaces specified, maximum is %d\n",
524 // MAX_NON_OLSR_IFS);
528 olsr_printf(1, "\nAdding interface '%s' to list of interface\n", ifName);
530 strncpy(NonOlsrIfNames[nNonOlsrIfs], ifName, IFNAMSIZ - 1);
531 NonOlsrIfNames[nNonOlsrIfs][IFNAMSIZ - 1] = '\0'; /* Ensures null termination */
536 /* -------------------------------------------------------------------------
537 * Function : IsNonOlsrIf
538 * Description: Checks if a network interface is OLSR-enabled
539 * Input : ifName - network interface (e.g. "eth0")
541 * Return : true (1) or false (0)
542 * Data Used : NonOlsrIfNames
543 * ------------------------------------------------------------------------- */
545 IsNonOlsrIf(const char *ifName)
549 assert(ifName != NULL);
551 for (i = 0; i < nNonOlsrIfs; i++) {
552 if (strncmp(NonOlsrIfNames[i], ifName, IFNAMSIZ) == 0)