busybox/networking/udhcp/d6_socket.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Copyright (C) 2011 Denys Vlasenko.
   4 *
   5 * Licensed under GPLv2, see file LICENSE in this source tree.
   6 */
   7#include "common.h"
   8#include "d6_common.h"
   9#include <net/if.h>
  10#include <ifaddrs.h>
  11#include <netpacket/packet.h>
  12
  13int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_addr *nip6, uint8_t *mac)
  14{
  15        int retval = 3;
  16        struct ifaddrs *ifap, *ifa;
  17
  18        getifaddrs(&ifap);
  19        for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
  20                struct sockaddr_in6 *sip6;
  21
  22                if (!ifa->ifa_addr || (strcmp(ifa->ifa_name, interface) != 0))
  23                        continue;
  24
  25                sip6 = (struct sockaddr_in6*)(ifa->ifa_addr);
  26
  27                if (ifa->ifa_addr->sa_family == AF_PACKET) {
  28                        struct sockaddr_ll *sll = (struct sockaddr_ll*)(ifa->ifa_addr);
  29                        memcpy(mac, sll->sll_addr, 6);
  30                        log2("MAC %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  31                        *ifindex = sll->sll_ifindex;
  32                        log2("ifindex %d", *ifindex);
  33                        retval &= (3 - (1<<0));
  34                }
  35#if 0
  36                if (ifa->ifa_addr->sa_family == AF_INET) {
  37                        *nip = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
  38                        log1("IP %s", inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr));
  39                }
  40#endif
  41                if (ifa->ifa_addr->sa_family == AF_INET6
  42                 && IN6_IS_ADDR_LINKLOCAL(&sip6->sin6_addr)
  43                ) {
  44                        *nip6 = sip6->sin6_addr; /* struct copy */
  45                        log1(
  46                                "IPv6 %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
  47                                nip6->s6_addr[0], nip6->s6_addr[1],
  48                                nip6->s6_addr[2], nip6->s6_addr[3],
  49                                nip6->s6_addr[4], nip6->s6_addr[5],
  50                                nip6->s6_addr[6], nip6->s6_addr[7],
  51                                nip6->s6_addr[8], nip6->s6_addr[9],
  52                                nip6->s6_addr[10], nip6->s6_addr[11],
  53                                nip6->s6_addr[12], nip6->s6_addr[13],
  54                                nip6->s6_addr[14], nip6->s6_addr[15]
  55                        );
  56                        retval &= (3 - (1<<1));
  57                }
  58        }
  59        freeifaddrs(ifap);
  60
  61        if (retval & (1<<0)) {
  62                /* This iface has no MAC (e.g. ppp), generate a random one */
  63                struct ifreq ifr;
  64                int fd;
  65
  66                /*memset(&ifr, 0, sizeof(ifr)); - SIOCGIFINDEX does not need to clear all */
  67                strncpy_IFNAMSIZ(ifr.ifr_name, interface);
  68                fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
  69                if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
  70                        *ifindex = ifr.ifr_ifindex;
  71                        log2("ifindex %d", *ifindex);
  72                        if (((uint32_t*)mac)[0] == 0) {
  73                                /* invent a fictitious MAC (once) */
  74                                ((uint32_t*)mac)[0] = rand();
  75                                ((uint16_t*)mac)[2] = rand();
  76                                mac[0] &= 0xfc; /* make sure it's not bcast */
  77                        }
  78                        retval &= (3 - (1<<0));
  79                }
  80                close(fd);
  81        }
  82
  83        if (retval == 0)
  84                return retval;
  85
  86        if (retval & (1<<0))
  87                bb_error_msg("can't get %s", "MAC");
  88        if (retval & (1<<1))
  89                bb_error_msg("can't get %s", "link-local IPv6 address");
  90        return -1;
  91}
  92
  93int FAST_FUNC d6_listen_socket(int port, const char *inf)
  94{
  95        int fd;
  96        struct sockaddr_in6 addr;
  97
  98        log1("opening listen socket on *:%d %s", port, inf);
  99        fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
 100
 101        setsockopt_reuseaddr(fd);
 102        if (setsockopt_broadcast(fd) == -1)
 103                bb_perror_msg_and_die("SO_BROADCAST");
 104
 105        /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */
 106        if (setsockopt_bindtodevice(fd, inf))
 107                xfunc_die(); /* warning is already printed */
 108
 109        memset(&addr, 0, sizeof(addr));
 110        addr.sin6_family = AF_INET6;
 111        addr.sin6_port = htons(port);
 112        /* addr.sin6_addr is all-zeros */
 113        xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
 114
 115        return fd;
 116}
 117