2 * The olsr.org Optimized Link-State Routing daemon(olsrd)
3 * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
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.
39 * $Id: net.c,v 1.31 2006/11/05 23:03:56 bernd67 Exp $
49 #include "../net_os.h"
50 #include "../parser.h"
54 *Wireless definitions for ioctl calls
55 *(from linux/wireless.h)
57 #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
58 #define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */
61 *Bind a socket to a device
63 *@param sock the socket to bind
64 *@param dev_name name of the device
66 *@return negative if error
70 bind_socket_to_device(int sock, char *dev_name)
73 *Bind to device using the SO_BINDTODEVICE flag
75 OLSR_PRINTF(3, "Binding socket %d to device %s\n", sock, dev_name)
76 return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name)+1);
84 *Enable IP forwarding.
85 *Just writing "1" to the /proc/sys/net/ipv4/ip_forward
86 *if using IPv4 or /proc/sys/net/ipv6/conf/all/forwarding
88 *Could probably drop the check for
89 *"0" here and write "1" anyways.
91 *@param version IP version.
93 *@return 1 on sucess 0 on failiure
96 enable_ip_forwarding(int version)
99 char procfile[FILENAME_MAX];
101 if(version == AF_INET)
103 strncpy(procfile, "/proc/sys/net/ipv4/ip_forward", FILENAME_MAX);
106 if(version == AF_INET6)
108 strncpy(procfile, "/proc/sys/net/ipv6/conf/all/forwarding", FILENAME_MAX);
114 if ((proc_fwd=fopen(procfile, "r"))==NULL)
117 if(version == AF_INET)
118 fprintf(stderr, "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n", procfile);
121 fprintf(stderr, "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv6?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n", procfile);
129 orig_fwd_state = fgetc(proc_fwd);
131 if(orig_fwd_state == '1')
133 OLSR_PRINTF(3, "\nIP forwarding is enabled on this system\n")
137 if ((proc_fwd=fopen(procfile, "w"))==NULL)
139 fprintf(stderr, "Could not open %s for writing!\n", procfile);
140 fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n");
146 syslog(LOG_INFO, "Writing \"1\" to %s\n", procfile);
147 fputs("1", proc_fwd);
159 disable_redirects_global(int version)
162 char procfile[FILENAME_MAX];
164 if(version == AF_INET6)
167 strcpy(procfile, "/proc/sys/net/ipv4/conf/all/send_redirects");
169 if((proc_redirect = fopen(procfile, "r")) == NULL)
171 fprintf(stderr, "WARNING! Could not open the %s file to check/disable ICMP redirects!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that ICMP redirects are disabled!\n\n", procfile);
178 orig_global_redirect_state = fgetc(proc_redirect);
179 fclose(proc_redirect);
182 if(orig_global_redirect_state == '0')
187 if ((proc_redirect = fopen(procfile, "w"))==NULL)
189 fprintf(stderr, "Could not open %s for writing!\n", procfile);
190 fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
196 syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
197 fputs("0", proc_redirect);
199 fclose(proc_redirect);
207 *@return 1 on sucess 0 on failiure
210 disable_redirects(char *if_name, int index, int version)
213 char procfile[FILENAME_MAX];
215 if(version == AF_INET6)
218 /* Generate the procfile name */
219 sprintf(procfile, REDIRECT_PROC, if_name);
222 if((proc_redirect = fopen(procfile, "r")) == NULL)
224 fprintf(stderr, "WARNING! Could not open the %s file to check/disable ICMP redirects!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that ICMP redirects are disabled!\n\n", procfile);
231 nic_states[index].redirect = fgetc(proc_redirect);
232 fclose(proc_redirect);
236 if ((proc_redirect = fopen(procfile, "w"))==NULL)
238 fprintf(stderr, "Could not open %s for writing!\n", procfile);
239 fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
245 syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
246 fputs("0", proc_redirect);
248 fclose(proc_redirect);
257 *@return 1 on sucess 0 on failiure
260 deactivate_spoof(char *if_name, int index, int version)
263 char procfile[FILENAME_MAX];
265 if(version == AF_INET6)
269 /* Generate the procfile name */
270 sprintf(procfile, SPOOF_PROC, if_name);
273 if((proc_spoof = fopen(procfile, "r")) == NULL)
275 fprintf(stderr, "WARNING! Could not open the %s file to check/disable the IP spoof filter!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabled!\n\n", procfile);
282 nic_states[index].spoof = fgetc(proc_spoof);
287 if ((proc_spoof = fopen(procfile, "w")) == NULL)
289 fprintf(stderr, "Could not open %s for writing!\n", procfile);
290 fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabeled!\n\n");
296 syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
297 fputs("0", proc_spoof);
307 *Resets the spoof filter and ICMP redirect settings
311 restore_settings(int version)
314 char procfile[FILENAME_MAX];
315 struct interface *ifs;
317 OLSR_PRINTF(1, "Restoring network state\n")
319 /* Restore IP forwarding to "off" */
320 if(orig_fwd_state == '0')
322 if(version == AF_INET)
324 strcpy(procfile, "/proc/sys/net/ipv4/ip_forward");
326 else if(version == AF_INET6)
328 strcpy(procfile, "/proc/sys/net/ipv6/conf/all/forwarding");
331 if ((proc_fd = fopen(procfile, "w")) == NULL)
333 fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
337 syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_fwd_state);
338 fputc(orig_fwd_state, proc_fd);
344 /* Restore global ICMP redirect setting */
345 if(orig_global_redirect_state != '0')
347 if(version == AF_INET)
349 strcpy(procfile, "/proc/sys/net/ipv4/conf/all/send_redirects");
351 if ((proc_fd = fopen(procfile, "w")) == NULL)
353 fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
357 syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_global_redirect_state);
358 fputc(orig_global_redirect_state, proc_fd);
365 if(version == AF_INET6)
368 for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
370 /* Discard host-emulation interfaces */
375 /* Generate the procfile name */
376 sprintf(procfile, REDIRECT_PROC, ifs->int_name);
378 if ((proc_fd = fopen(procfile, "w")) == NULL)
380 fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
384 syslog(LOG_INFO, "Resetting %s to %c\n", procfile, nic_states[ifs->if_nr].redirect);
386 fputc(nic_states[ifs->if_nr].redirect, proc_fd);
393 /* Generate the procfile name */
394 sprintf(procfile, SPOOF_PROC, ifs->int_name);
396 if ((proc_fd = fopen(procfile, "w")) == NULL)
398 fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
402 syslog(LOG_INFO, "Resetting %s to %c\n", procfile, nic_states[ifs->if_nr].spoof);
404 fputc(nic_states[ifs->if_nr].spoof, proc_fd);
415 *Creates a nonblocking broadcast socket.
416 *@param sa sockaddr struct. Used for bind(2).
417 *@return the FD of the socket or -1 on error.
420 gethemusocket(struct sockaddr_in *pin)
424 OLSR_PRINTF(1, " Connecting to switch daemon port 10150...");
427 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
430 syslog(LOG_ERR, "hcsocket: %m");
434 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
436 perror("SO_REUSEADDR failed");
440 /* connect to PORT on HOST */
441 if (connect(sock,(struct sockaddr *) pin, sizeof(*pin)) < 0)
444 fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
445 printf("connection refused\n");
452 /* Keep TCP socket blocking */
458 *Creates a nonblocking broadcast socket.
459 *@param sa sockaddr struct. Used for bind(2).
460 *@return the FD of the socket or -1 on error.
463 getsocket(struct sockaddr *sa, int bufspace, char *int_name)
465 struct sockaddr_in *sin=(struct sockaddr_in *)sa;
470 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
473 syslog(LOG_ERR, "socket: %m");
480 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
482 perror("setsockopt");
483 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
489 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
491 perror("SO_REUSEADDR failed");
500 for (on = bufspace; ; on -= 1024)
502 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
503 &on, sizeof (on)) == 0)
507 perror("setsockopt");
508 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
518 * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
522 if(bind_socket_to_device(sock, int_name) < 0)
524 fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
525 syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
531 if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0)
534 syslog(LOG_ERR, "bind: %m");
540 *One should probably fetch the flags first
543 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
544 syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
551 *Creates a nonblocking IPv6 socket
552 *@param sin sockaddr_in6 struct. Used for bind(2).
553 *@return the FD of the socket or -1 on error.
556 getsocket6(struct sockaddr_in6 *sin, int bufspace, char *int_name)
562 if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
565 syslog(LOG_ERR, "socket: %m");
570 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
572 perror("setsockopt(IPV6_V6ONLY)");
573 syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
578 //#ifdef SO_BROADCAST
580 if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
582 perror("setsockopt");
583 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
594 for (on = bufspace; ; on -= 1024)
596 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
597 &on, sizeof (on)) == 0)
601 perror("setsockopt");
602 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
610 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
612 perror("SO_REUSEADDR failed");
619 * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
623 if(bind_socket_to_device(sock, int_name) < 0)
625 fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
626 syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
632 if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0)
635 syslog(LOG_ERR, "bind: %m");
641 *One should probably fetch the flags first
644 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
645 syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
654 join_mcast(struct interface *ifs, int sock)
656 /* See linux/in6.h */
658 struct ipv6_mreq mcastreq;
660 COPY_IP(&mcastreq.ipv6mr_multiaddr, &ifs->int6_multaddr.sin6_addr);
661 mcastreq.ipv6mr_interface = ifs->if_index;
663 #if !defined __FreeBSD__ && !defined __MacOSX__ && !defined __NetBSD__
664 OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name, olsr_ip_to_string((union olsr_ip_addr *)&ifs->int6_multaddr.sin6_addr))
670 sizeof(struct ipv6_mreq))
673 perror("Join multicast");
677 #warning implement IPV6_ADD_MEMBERSHIP
681 #ifdef IPV6_JOIN_GROUP
682 /* Join reciever group */
687 sizeof(struct ipv6_mreq))
690 /* Join reciever group */
695 sizeof(struct ipv6_mreq))
699 perror("Join multicast send");
707 (char *)&mcastreq.ipv6mr_interface,
708 sizeof(mcastreq.ipv6mr_interface))
711 perror("Set multicast if");
716 OLSR_PRINTF(3, "OK\n")
723 *From net-tools lib/interface.c
728 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
730 char addr6[40], devname[IFNAMSIZ];
732 int plen, scope, dad_status, if_idx;
734 struct sockaddr_in6 tmp_sockaddr6;
736 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL)
738 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
739 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
740 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
741 &if_idx, &plen, &scope, &dad_status, devname) != EOF)
743 if (!strcmp(devname, ifname))
745 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
746 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
747 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
748 OLSR_PRINTF(5, "\tinet6 addr: %s\n", addr6)
749 OLSR_PRINTF(5, "\tScope: %d\n", scope)
750 if(scope == scope_in)
752 OLSR_PRINTF(4, "Found addr: %s:%s:%s:%s:%s:%s:%s:%s\n",
753 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
754 addr6p[4], addr6p[5], addr6p[6], addr6p[7])
755 inet_pton(AF_INET6,addr6,&tmp_sockaddr6);
756 memcpy(&saddr6->sin6_addr, &tmp_sockaddr6, sizeof(struct in6_addr));
770 * Wrapper for sendto(2)
778 const struct sockaddr *to,
781 return sendto(s, buf, len, flags, to, tolen);
785 * Wrapper for recvfrom(2)
793 struct sockaddr *from,
805 * Wrapper for select(2)
809 olsr_select(int nfds,
813 struct timeval *timeout)
823 check_wireless_interface(char *ifname)
827 memset(&ifr, 0, sizeof(ifr));
828 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
830 return (ioctl(olsr_cnf->ioctl_s, SIOCGIWNAME, &ifr) >= 0) ? 1 : 0;
835 #include <linux/sockios.h>
836 #include <linux/types.h>
838 /* This data structure is used for all the MII ioctl's */
847 /* Basic Mode Control Register */
848 #define MII_BMCR 0x00
849 #define MII_BMCR_RESET 0x8000
850 #define MII_BMCR_LOOPBACK 0x4000
851 #define MII_BMCR_100MBIT 0x2000
852 #define MII_BMCR_AN_ENA 0x1000
853 #define MII_BMCR_ISOLATE 0x0400
854 #define MII_BMCR_RESTART 0x0200
855 #define MII_BMCR_DUPLEX 0x0100
856 #define MII_BMCR_COLTEST 0x0080
858 /* Basic Mode Status Register */
859 #define MII_BMSR 0x01
860 #define MII_BMSR_CAP_MASK 0xf800
861 #define MII_BMSR_100BASET4 0x8000
862 #define MII_BMSR_100BASETX_FD 0x4000
863 #define MII_BMSR_100BASETX_HD 0x2000
864 #define MII_BMSR_10BASET_FD 0x1000
865 #define MII_BMSR_10BASET_HD 0x0800
866 #define MII_BMSR_NO_PREAMBLE 0x0040
867 #define MII_BMSR_AN_COMPLETE 0x0020
868 #define MII_BMSR_REMOTE_FAULT 0x0010
869 #define MII_BMSR_AN_ABLE 0x0008
870 #define MII_BMSR_LINK_VALID 0x0004
871 #define MII_BMSR_JABBER 0x0002
872 #define MII_BMSR_EXT_CAP 0x0001
875 calculate_if_metric(char *ifname)
877 if(check_wireless_interface(ifname))
880 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
883 if(ioctl(olsr_cnf->ioctl_s, SIOCGIWRATE, &ifr) < 0)
885 OLSR_PRINTF(1, "Not able to find rate for WLAN interface %s\n", ifname)
886 return WEIGHT_WLAN_11MB;
889 OLSR_PRINTF(1, "Bitrate %d\n", ifr.ifr_ifru.ifru_ivalue)
891 //WEIGHT_WLAN_LOW, /* <11Mb WLAN */
892 //WEIGHT_WLAN_11MB, /* 11Mb 802.11b */
893 //WEIGHT_WLAN_54MB, /* 54Mb 802.11g */
894 return WEIGHT_WLAN_LOW;
901 struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
903 memset(&ifr, 0, sizeof(ifr));
904 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
906 if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
908 OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n",
909 ifr.ifr_name, strerror(errno))
910 return WEIGHT_ETHERNET_DEFAULT;
913 mii->reg_num = MII_BMCR;
914 if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
915 OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
917 return WEIGHT_ETHERNET_DEFAULT;
922 OLSR_PRINTF(1, "%s: ", ifr.ifr_name)
923 OLSR_PRINTF(1, "%s Mbit, %s duplex\n",
924 (bmcr & MII_BMCR_100MBIT) ? "100" : "10",
925 (bmcr & MII_BMCR_DUPLEX) ? "full" : "half")
927 is_if_link_up(ifname);
929 if(mii->val_out & MII_BMCR_100MBIT)
930 return WEIGHT_ETHERNET_100MB;
932 return WEIGHT_ETHERNET_10MB;
933 //WEIGHT_ETHERNET_1GB, /* Ethernet 1Gb */
940 is_if_link_up(char *ifname)
942 if(check_wireless_interface(ifname))
944 /* No link checking on wireless devices */
951 struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
953 memset(&ifr, 0, sizeof(ifr));
954 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
956 if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIPHY, &ifr) < 0) {
958 OLSR_PRINTF(1, "SIOCGMIIPHY on '%s' failed: %s\n",
959 ifr.ifr_name, strerror(errno))
960 return WEIGHT_ETHERNET_DEFAULT;
962 mii->reg_num = MII_BMSR;
963 if (ioctl(olsr_cnf->ioctl_s, SIOCGMIIREG, &ifr) < 0) {
964 OLSR_PRINTF(1, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
966 return WEIGHT_ETHERNET_DEFAULT;
970 OLSR_PRINTF(1, "%s: ", ifr.ifr_name)
971 OLSR_PRINTF(1, "%s\n", (bmsr & MII_BMSR_LINK_VALID) ? "link ok " : "no link ")
973 return (bmsr & MII_BMSR_LINK_VALID);
980 calculate_if_metric(char *ifname)
982 return check_wireless_interface(ifname);