From b1c8fff811e708507cdfdbabfad2baba7dc7447f Mon Sep 17 00:00:00 2001 From: sdhsdh Date: Tue, 20 Jan 2009 00:32:00 +0000 Subject: [PATCH] missing --- support/sdk/c/blip/driver/radvd-1.0/device.c | 298 +++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 support/sdk/c/blip/driver/radvd-1.0/device.c diff --git a/support/sdk/c/blip/driver/radvd-1.0/device.c b/support/sdk/c/blip/driver/radvd-1.0/device.c new file mode 100644 index 00000000..f160c15b --- /dev/null +++ b/support/sdk/c/blip/driver/radvd-1.0/device.c @@ -0,0 +1,298 @@ +/* + * $Id$ + * + * Authors: + * Lars Fenneberg + * + * This software is Copyright 1996,1997 by the above mentioned author(s), + * All Rights Reserved. + * + * The license which is distributed with this software in the file COPYRIGHT + * applies to this software. If your distribution is missing this file, you + * may request it from . + * + */ + +#include +#include +#include +#include +#include /* for PATH_PROC_NET_IF_INET6 */ + +#ifndef IPV6_ADDR_LINKLOCAL +#define IPV6_ADDR_LINKLOCAL 0x0020U +#endif + +/* + * this function gets the hardware type and address of an interface, + * determines the link layer token length and checks it against + * the defined prefixes + */ +int +setup_deviceinfo(int sock, struct Interface *iface) +{ + struct ifreq ifr; + struct AdvPrefix *prefix; + char zero[sizeof(iface->if_addr)]; + + strncpy(ifr.ifr_name, iface->Name, IFNAMSIZ-1); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + + if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) { + flog(LOG_ERR, "ioctl(SIOCGIFMTU) failed for %s: %s", + iface->Name, strerror(errno)); + return (-1); + } + + dlog(LOG_DEBUG, 3, "mtu for %s is %d", iface->Name, ifr.ifr_mtu); + iface->if_maxmtu = ifr.ifr_mtu; + + if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) + { + flog(LOG_ERR, "ioctl(SIOCGIFHWADDR) failed for %s: %s", + iface->Name, strerror(errno)); + return (-1); + } + + dlog(LOG_DEBUG, 3, "hardware type for %s is %d", iface->Name, + ifr.ifr_hwaddr.sa_family); + + switch(ifr.ifr_hwaddr.sa_family) + { + case ARPHRD_ETHER: + iface->if_hwaddr_len = 48; + iface->if_prefix_len = 64; + break; +#ifdef ARPHRD_FDDI + case ARPHRD_FDDI: + iface->if_hwaddr_len = 48; + iface->if_prefix_len = 64; + break; +#endif /* ARPHDR_FDDI */ +#ifdef ARPHRD_ARCNET + case ARPHRD_ARCNET: + iface->if_hwaddr_len = 8; + iface->if_prefix_len = -1; + iface->if_maxmtu = -1; + break; +#endif /* ARPHDR_ARCNET */ + default: + iface->if_hwaddr_len = -1; + iface->if_prefix_len = -1; + iface->if_maxmtu = -1; + break; + } + + dlog(LOG_DEBUG, 3, "link layer token length for %s is %d", iface->Name, + iface->if_hwaddr_len); + + dlog(LOG_DEBUG, 3, "prefix length for %s is %d", iface->Name, + iface->if_prefix_len); + + if (iface->if_hwaddr_len != -1) { + unsigned int if_hwaddr_len_bytes = (iface->if_hwaddr_len + 7) >> 3; + + if (if_hwaddr_len_bytes > sizeof(iface->if_hwaddr)) { + flog(LOG_ERR, "address length %d too big for %s", if_hwaddr_len_bytes, iface->Name); + return(-2); + } + memcpy(iface->if_hwaddr, ifr.ifr_hwaddr.sa_data, if_hwaddr_len_bytes); + + memset(zero, 0, sizeof(zero)); + if (!memcmp(iface->if_hwaddr, zero, if_hwaddr_len_bytes)) + flog(LOG_WARNING, "WARNING, MAC address on %s is all zero!", + iface->Name); + } + + prefix = iface->AdvPrefixList; + while (prefix) + { + if ((iface->if_prefix_len != -1) && + (iface->if_prefix_len != prefix->PrefixLen)) + { + flog(LOG_WARNING, "prefix length should be %d for %s", + iface->if_prefix_len, iface->Name); + } + + prefix = prefix->next; + } + + return (0); +} + +/* + * this function extracts the link local address and interface index + * from PATH_PROC_NET_IF_INET6. Note: 'sock' unused in Linux. + */ +int setup_linklocal_addr(int sock, struct Interface *iface) +{ + FILE *fp; + char str_addr[40]; + unsigned int plen, scope, dad_status, if_idx; + char devname[IFNAMSIZ]; + + if ((fp = fopen(PATH_PROC_NET_IF_INET6, "r")) == NULL) + { + flog(LOG_ERR, "can't open %s: %s", PATH_PROC_NET_IF_INET6, + strerror(errno)); + return (-1); + } + + while (fscanf(fp, "%32s %x %02x %02x %02x %15s\n", + str_addr, &if_idx, &plen, &scope, &dad_status, + devname) != EOF) + { + if (scope == IPV6_ADDR_LINKLOCAL && + strcmp(devname, iface->Name) == 0) + { + struct in6_addr addr; + unsigned int ap; + int i; + + for (i=0; i<16; i++) + { + sscanf(str_addr + i * 2, "%02x", &ap); + addr.s6_addr[i] = (unsigned char)ap; + } + memcpy(&iface->if_addr, &addr, sizeof(iface->if_addr)); + + iface->if_index = if_idx; + fclose(fp); + return 0; + } + } + + flog(LOG_ERR, "no linklocal address configured for %s", iface->Name); + fclose(fp); + return (-1); +} + +int setup_allrouters_membership(int sock, struct Interface *iface) +{ + struct ipv6_mreq mreq; + + memset(&mreq, 0, sizeof(mreq)); + mreq.ipv6mr_interface = iface->if_index; + + /* ipv6-allrouters: ff02::2 */ + mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xFF020000); + mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x2); + + if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + /* linux-2.6.12-bk4 returns error with HUP signal but keep listening */ + if (errno != EADDRINUSE) + { + flog(LOG_ERR, "can't join ipv6-allrouters on %s", iface->Name); + return (-1); + } + } + + return (0); +} + +int check_allrouters_membership(int sock, struct Interface *iface) +{ + #define ALL_ROUTERS_MCAST "ff020000000000000000000000000002" + + FILE *fp; + unsigned int if_idx, allrouters_ok=0; + char addr[32+1]; + int ret=0; + + if ((fp = fopen(PATH_PROC_NET_IGMP6, "r")) == NULL) + { + flog(LOG_ERR, "can't open %s: %s", PATH_PROC_NET_IGMP6, + strerror(errno)); + return (-1); + } + + while ( (ret=fscanf(fp, "%u %*s %32[0-9A-Fa-f] %*x %*x %*x\n", &if_idx, addr)) != EOF) { + if (ret == 2) { + if (iface->if_index == if_idx) { + if (strncmp(addr, ALL_ROUTERS_MCAST, sizeof(addr)) == 0) + allrouters_ok = 1; + } + } + } + + fclose(fp); + + if (!allrouters_ok) { + flog(LOG_WARNING, "resetting ipv6-allrouters membership on %s", iface->Name); + setup_allrouters_membership(sock, iface); + } + + return(0); +} + +static int +set_interface_var(const char *iface, + const char *var, const char *name, + uint32_t val) +{ + FILE *fp; + char spath[64+IFNAMSIZ]; /* XXX: magic constant */ + snprintf(spath, sizeof(spath), var, iface); + + fp = fopen(spath, "w"); + if (!fp) { + if (name) + flog(LOG_ERR, "failed to set %s (%u) for %s", + name, val, iface); + return -1; + } + fprintf(fp, "%u", val); + fclose(fp); + + return 0; +} + +int +set_interface_linkmtu(const char *iface, uint32_t mtu) +{ + return set_interface_var(iface, + PROC_SYS_IP6_LINKMTU, "LinkMTU", + mtu); +} + +int +set_interface_curhlim(const char *iface, uint8_t hlim) +{ + return set_interface_var(iface, + PROC_SYS_IP6_CURHLIM, "CurHopLimit", + hlim); +} + +int +set_interface_reachtime(const char *iface, uint32_t rtime) +{ + int ret; + ret = set_interface_var(iface, + PROC_SYS_IP6_BASEREACHTIME_MS, + NULL, + rtime); + if (ret) + ret = set_interface_var(iface, + PROC_SYS_IP6_BASEREACHTIME, + "BaseReachableTimer", + rtime / 1000); + return ret; +} + +int +set_interface_retranstimer(const char *iface, uint32_t rettimer) +{ + int ret; + ret = set_interface_var(iface, + PROC_SYS_IP6_RETRANSTIMER_MS, + NULL, + rettimer); + if (ret) + ret = set_interface_var(iface, + PROC_SYS_IP6_RETRANSTIMER, + "RetransTimer", + rettimer / 1000); + return ret; +} + -- 2.39.2