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(
  14                const char *interface,
  15                int *ifindex,
  16                struct in6_addr *nip6,
  17                uint8_t *mac)
  18{
  19        int retval = 3;
  20        struct ifaddrs *ifap, *ifa;
  21
  22        getifaddrs(&ifap);
  23        for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
  24                struct sockaddr_in6 *sip6;
  25
  26                if (!ifa->ifa_addr || (strcmp(ifa->ifa_name, interface) != 0))
  27                        continue;
  28
  29                if (ifa->ifa_addr->sa_family == AF_PACKET) {
  30                        struct sockaddr_ll *sll = (void*)(ifa->ifa_addr);
  31                        memcpy(mac, sll->sll_addr, 6);
  32                        log2("MAC %02x:%02x:%02x:%02x:%02x:%02x",
  33                                mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
  34                        );
  35                        *ifindex = sll->sll_ifindex;
  36                        log2("ifindex %d", *ifindex);
  37                        retval &= (3 - (1<<0));
  38                }
  39#if 0
  40                if (ifa->ifa_addr->sa_family == AF_INET) {
  41                        *nip = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
  42                        log1("IP %s", inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr));
  43                }
  44#endif
  45/* RFC 3315
  46 * 16. Client Source Address and Interface Selection
  47 *
  48 * "When a client sends a DHCP message to the
  49 * All_DHCP_Relay_Agents_and_Servers address, ... ... The client
  50 * MUST use a link-local address assigned to the interface for which it
  51 * is requesting configuration information as the source address in the
  52 * header of the IP datagram."
  53 */
  54                sip6 = (void*)(ifa->ifa_addr);
  55
  56                if (ifa->ifa_addr->sa_family == AF_INET6
  57                 && IN6_IS_ADDR_LINKLOCAL(&sip6->sin6_addr)
  58                ) {
  59                        *nip6 = sip6->sin6_addr; /* struct copy */
  60                        log1(
  61                                "IPv6 %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
  62                                nip6->s6_addr[0], nip6->s6_addr[1],
  63                                nip6->s6_addr[2], nip6->s6_addr[3],
  64                                nip6->s6_addr[4], nip6->s6_addr[5],
  65                                nip6->s6_addr[6], nip6->s6_addr[7],
  66                                nip6->s6_addr[8], nip6->s6_addr[9],
  67                                nip6->s6_addr[10], nip6->s6_addr[11],
  68                                nip6->s6_addr[12], nip6->s6_addr[13],
  69                                nip6->s6_addr[14], nip6->s6_addr[15]
  70                        );
  71                        retval &= (3 - (1<<1));
  72                }
  73        }
  74        freeifaddrs(ifap);
  75
  76        if (retval & (1<<0)) {
  77                /* This iface has no MAC (e.g. ppp), generate a random one */
  78                struct ifreq ifr;
  79                int fd;
  80
  81                /*memset(&ifr, 0, sizeof(ifr)); - SIOCGIFINDEX does not need to clear all */
  82                strncpy_IFNAMSIZ(ifr.ifr_name, interface);
  83                fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
  84                if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
  85                        *ifindex = ifr.ifr_ifindex;
  86                        log2("ifindex %d", *ifindex);
  87                        if (((uint32_t*)mac)[0] == 0) {
  88                                /* invent a fictitious MAC (once) */
  89                                ((uint32_t*)mac)[0] = rand();
  90                                ((uint16_t*)mac)[2] = rand();
  91                                mac[0] &= 0xfc; /* make sure it's not bcast */
  92                        }
  93                        retval &= (3 - (1<<0));
  94                }
  95                close(fd);
  96        }
  97
  98        if (retval == 0)
  99                return retval;
 100
 101        if (retval & (1<<0))
 102                bb_error_msg("can't get %s", "MAC");
 103        if (retval & (1<<1))
 104                bb_error_msg("can't get %s", "link-local IPv6 address");
 105        return retval;
 106}
 107
 108int FAST_FUNC d6_listen_socket(int port, const char *inf)
 109{
 110        int fd;
 111        struct sockaddr_in6 addr;
 112
 113        log1("opening listen socket on *:%d %s", port, inf);
 114        fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
 115
 116        setsockopt_reuseaddr(fd);
 117        if (setsockopt_broadcast(fd) == -1)
 118                bb_simple_perror_msg_and_die("SO_BROADCAST");
 119
 120        /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */
 121        if (setsockopt_bindtodevice(fd, inf))
 122                xfunc_die(); /* warning is already printed */
 123
 124        memset(&addr, 0, sizeof(addr));
 125        addr.sin6_family = AF_INET6;
 126        addr.sin6_port = htons(port);
 127        /* addr.sin6_addr is all-zeros */
 128        xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
 129
 130        return fd;
 131}
 132