source: rtems-libbsd/dhcpcd/net.c @ 7e52ab9

55-freebsd-126-freebsd-12
Last change on this file since 7e52ab9 was f2ed769, checked in by Sebastian Huber <sebastian.huber@…>, on 01/30/14 at 12:29:46

DHCPCD(8): Import

Import DHCPCD(8) from:

http://roy.marples.name/projects/dhcpcd/

The upstream sources can be obtained via:

fossil clone http://roy.marples.name/projects/dhcpcd

The imported version is 2014-01-29 19:46:44 [6b209507bb].

  • Property mode set to 100644
File size: 11.9 KB
Line 
1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/param.h>
29#include <sys/types.h>
30#include <sys/ioctl.h>
31#include <sys/socket.h>
32
33#include <net/if.h>
34#include <net/if_arp.h>
35#include <netinet/in.h>
36#ifdef __FreeBSD__ /* Needed so that including netinet6/in6_var.h works */
37#  include <net/if_var.h>
38#endif
39#ifdef AF_LINK
40#  include <net/if_dl.h>
41#  include <net/if_types.h>
42#  include <netinet/in_var.h>
43#endif
44#ifdef AF_PACKET
45#  include <netpacket/packet.h>
46#endif
47#ifdef SIOCGIFMEDIA
48#  include <net/if_media.h>
49#endif
50
51#include <net/route.h>
52#ifdef __linux__
53#  include <asm/types.h> /* for systems with broken headers */
54#  include <linux/rtnetlink.h>
55#endif
56
57#include <ctype.h>
58#include <errno.h>
59#include <ifaddrs.h>
60#include <fnmatch.h>
61#include <stddef.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <syslog.h>
66#include <unistd.h>
67
68#include "config.h"
69#include "common.h"
70#include "dev.h"
71#include "dhcp.h"
72#include "dhcp6.h"
73#include "if-options.h"
74#include "ipv4.h"
75#include "ipv6nd.h"
76#include "net.h"
77
78int socket_afnet = -1;
79
80static char hwaddr_buffer[(HWADDR_LEN * 3) + 1 + 1024];
81
82char *
83hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
84{
85        char *p = hwaddr_buffer;
86        size_t i;
87
88        for (i = 0; i < hwlen; i++) {
89                if (i > 0)
90                        *p ++= ':';
91                p += snprintf(p, 3, "%.2x", hwaddr[i]);
92        }
93
94        *p ++= '\0';
95
96        return hwaddr_buffer;
97}
98
99size_t
100hwaddr_aton(unsigned char *buffer, const char *addr)
101{
102        char c[3];
103        const char *p = addr;
104        unsigned char *bp = buffer;
105        size_t len = 0;
106
107        c[2] = '\0';
108        while (*p) {
109                c[0] = *p++;
110                c[1] = *p++;
111                /* Ensure that digits are hex */
112                if (isxdigit((unsigned char)c[0]) == 0 ||
113                    isxdigit((unsigned char)c[1]) == 0)
114                {
115                        errno = EINVAL;
116                        return 0;
117                }
118                /* We should have at least two entries 00:01 */
119                if (len == 0 && *p == '\0') {
120                        errno = EINVAL;
121                        return 0;
122                }
123                /* Ensure that next data is EOL or a seperator with data */
124                if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
125                        errno = EINVAL;
126                        return 0;
127                }
128                if (*p)
129                        p++;
130                if (bp)
131                        *bp++ = (unsigned char)strtol(c, NULL, 16);
132                len++;
133        }
134        return len;
135}
136
137void
138free_interface(struct interface *ifp)
139{
140
141        if (ifp == NULL)
142                return;
143        ipv4_free(ifp);
144        dhcp_free(ifp);
145        ipv6_free(ifp);
146        dhcp6_free(ifp);
147        ipv6nd_free(ifp);
148        free_options(ifp->options);
149        free(ifp);
150}
151
152int
153carrier_status(struct interface *iface)
154{
155        int ret;
156        struct ifreq ifr;
157#ifdef SIOCGIFMEDIA
158        struct ifmediareq ifmr;
159#endif
160#ifdef __linux__
161        char *p;
162#endif
163
164        memset(&ifr, 0, sizeof(ifr));
165        strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
166#ifdef __linux__
167        /* We can only test the real interface up */
168        if ((p = strchr(ifr.ifr_name, ':')))
169                *p = '\0';
170#endif
171
172        if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1)
173                return LINK_UNKNOWN;
174        iface->flags = ifr.ifr_flags;
175
176        ret = LINK_UNKNOWN;
177#ifdef SIOCGIFMEDIA
178        memset(&ifmr, 0, sizeof(ifmr));
179        strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
180        if (ioctl(socket_afnet, SIOCGIFMEDIA, &ifmr) != -1 &&
181            ifmr.ifm_status & IFM_AVALID)
182                ret = (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN;
183#endif
184        if (ret == LINK_UNKNOWN)
185                ret = (ifr.ifr_flags & IFF_RUNNING) ? LINK_UP : LINK_DOWN;
186        return ret;
187}
188
189int
190up_interface(struct interface *iface)
191{
192        struct ifreq ifr;
193        int retval = -1;
194#ifdef __linux__
195        char *p;
196#endif
197
198        memset(&ifr, 0, sizeof(ifr));
199        strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
200#ifdef __linux__
201        /* We can only bring the real interface up */
202        if ((p = strchr(ifr.ifr_name, ':')))
203                *p = '\0';
204#endif
205        if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == 0) {
206                if ((ifr.ifr_flags & IFF_UP))
207                        retval = 0;
208                else {
209                        ifr.ifr_flags |= IFF_UP;
210                        if (ioctl(socket_afnet, SIOCSIFFLAGS, &ifr) == 0)
211                                retval = 0;
212                }
213                iface->flags = ifr.ifr_flags;
214        }
215        return retval;
216}
217
218struct if_head *
219discover_interfaces(int argc, char * const *argv)
220{
221        struct ifaddrs *ifaddrs, *ifa;
222        char *p;
223        int i, sdl_type;
224        struct if_head *ifs;
225        struct interface *ifp;
226#ifdef __linux__
227        char ifn[IF_NAMESIZE];
228#endif
229#ifdef INET
230        const struct sockaddr_in *addr;
231        const struct sockaddr_in *net;
232        const struct sockaddr_in *dst;
233#endif
234#ifdef INET6
235        const struct sockaddr_in6 *sin6;
236        int ifa_flags;
237#endif
238#ifdef AF_LINK
239        const struct sockaddr_dl *sdl;
240#ifdef IFLR_ACTIVE
241        struct if_laddrreq iflr;
242        int socket_aflink;
243
244        socket_aflink = socket(AF_LINK, SOCK_DGRAM, 0);
245        if (socket_aflink == -1)
246                return NULL;
247        memset(&iflr, 0, sizeof(iflr));
248#endif
249#elif AF_PACKET
250        const struct sockaddr_ll *sll;
251#endif
252
253        if (getifaddrs(&ifaddrs) == -1)
254                return NULL;
255
256        ifs = malloc(sizeof(*ifs));
257        if (ifs == NULL)
258                return NULL;
259        TAILQ_INIT(ifs);
260
261        for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
262                if (ifa->ifa_addr != NULL) {
263#ifdef AF_LINK
264                        if (ifa->ifa_addr->sa_family != AF_LINK)
265                                continue;
266#elif AF_PACKET
267                        if (ifa->ifa_addr->sa_family != AF_PACKET)
268                                continue;
269#endif
270                }
271
272                /* Ensure that the interface name has settled */
273                if (!dev_initialized(ifa->ifa_name))
274                        continue;
275
276                /* It's possible for an interface to have >1 AF_LINK.
277                 * For our purposes, we use the first one. */
278                TAILQ_FOREACH(ifp, ifs, next) {
279                        if (strcmp(ifp->name, ifa->ifa_name) == 0)
280                                break;
281                }
282                if (ifp)
283                        continue;
284                if (argc > 0) {
285                        for (i = 0; i < argc; i++) {
286#ifdef __linux__
287                                /* Check the real interface name */
288                                strlcpy(ifn, argv[i], sizeof(ifn));
289                                p = strchr(ifn, ':');
290                                if (p)
291                                        *p = '\0';
292                                if (strcmp(ifn, ifa->ifa_name) == 0)
293                                        break;
294#else
295                                if (strcmp(argv[i], ifa->ifa_name) == 0)
296                                        break;
297#endif
298                        }
299                        if (i == argc)
300                                continue;
301                        p = argv[i];
302                } else {
303                        p = ifa->ifa_name;
304                        /* -1 means we're discovering against a specific
305                         * interface, but we still need the below rules
306                         * to apply. */
307                        if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0)
308                                continue;
309                }
310                for (i = 0; i < ifdc; i++)
311                        if (!fnmatch(ifdv[i], p, 0))
312                                break;
313                if (i < ifdc)
314                        continue;
315                for (i = 0; i < ifac; i++)
316                        if (!fnmatch(ifav[i], p, 0))
317                                break;
318                if (ifac && i == ifac)
319                        continue;
320
321                if (if_vimaster(ifa->ifa_name) == 1) {
322                        syslog(argc ? LOG_ERR : LOG_DEBUG,
323                                "%s: is a Virtual Interface Master, skipping",
324                                ifa->ifa_name);
325                        continue;
326                }
327
328                ifp = calloc(1, sizeof(*ifp));
329                if (ifp == NULL)
330                        return NULL;
331                strlcpy(ifp->name, p, sizeof(ifp->name));
332                ifp->flags = ifa->ifa_flags;
333
334                /* Bring the interface up if not already */
335                if (!(ifp->flags & IFF_UP)
336#ifdef SIOCGIFMEDIA
337                    && carrier_status(ifp) != LINK_UNKNOWN
338#endif
339                   )
340                {
341                        if (up_interface(ifp) == 0)
342                                options |= DHCPCD_WAITUP;
343                        else
344                                syslog(LOG_ERR, "%s: up_interface: %m",
345                                    ifp->name);
346                }
347
348                sdl_type = 0;
349                /* Don't allow loopback unless explicit */
350                if (ifp->flags & IFF_LOOPBACK) {
351                        if (argc == 0 && ifac == 0) {
352                                free_interface(ifp);
353                                continue;
354                        }
355                } else if (ifa->ifa_addr != NULL) {
356#ifdef AF_LINK
357                        sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;
358
359#ifdef IFLR_ACTIVE
360                        /* We need to check for active address */
361                        strlcpy(iflr.iflr_name, ifp->name,
362                            sizeof(iflr.iflr_name));
363                        memcpy(&iflr.addr, ifa->ifa_addr,
364                            MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
365                        iflr.flags = IFLR_PREFIX;
366                        iflr.prefixlen = sdl->sdl_alen * NBBY;
367                        if (ioctl(socket_aflink, SIOCGLIFADDR, &iflr) == -1 ||
368                            !(iflr.flags & IFLR_ACTIVE))
369                        {
370                                free_interface(ifp);
371                                continue;
372                        }
373#endif
374
375                        ifp->index = sdl->sdl_index;
376                        sdl_type = sdl->sdl_type;
377                        switch(sdl->sdl_type) {
378                        case IFT_BRIDGE: /* FALLTHROUGH */
379                        case IFT_L2VLAN: /* FALLTHOUGH */
380                        case IFT_L3IPVLAN: /* FALLTHROUGH */
381                        case IFT_ETHER:
382                                ifp->family = ARPHRD_ETHER;
383                                break;
384                        case IFT_IEEE1394:
385                                ifp->family = ARPHRD_IEEE1394;
386                                break;
387#ifdef IFT_INFINIBAND
388                        case IFT_INFINIBAND:
389                                ifp->family = ARPHRD_INFINIBAND;
390                                break;
391#endif
392                        }
393                        ifp->hwlen = sdl->sdl_alen;
394#ifndef CLLADDR
395#  define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
396#endif
397                        memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
398#elif AF_PACKET
399                        sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr;
400                        ifp->index = sll->sll_ifindex;
401                        ifp->family = sdl_type = sll->sll_hatype;
402                        ifp->hwlen = sll->sll_halen;
403                        if (ifp->hwlen != 0)
404                                memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
405#endif
406                }
407#ifdef __linux__
408                /* PPP addresses on Linux don't have hardware addresses */
409                else
410                        ifp->index = if_nametoindex(ifp->name);
411#endif
412
413                /* We only work on ethernet by default */
414                if (!(ifp->flags & IFF_POINTOPOINT) &&
415                    ifp->family != ARPHRD_ETHER)
416                {
417                        if (argc == 0 && ifac == 0) {
418                                free_interface(ifp);
419                                continue;
420                        }
421                        switch (ifp->family) {
422                        case ARPHRD_IEEE1394: /* FALLTHROUGH */
423                        case ARPHRD_INFINIBAND:
424                                /* We don't warn for supported families */
425                                break;
426                        default:
427                                syslog(LOG_WARNING,
428                                    "%s: unsupported interface type %.2x"
429                                    ", falling back to ethernet",
430                                    ifp->name, sdl_type);
431                                ifp->family = ARPHRD_ETHER;
432                                break;
433                        }
434                }
435
436                /* Handle any platform init for the interface */
437                if (if_init(ifp) == -1) {
438                        syslog(LOG_ERR, "%s: if_init: %m", p);
439                        free_interface(ifp);
440                        continue;
441                }
442
443                /* Ensure that the MTU is big enough for DHCP */
444                if (get_mtu(ifp->name) < MTU_MIN &&
445                    set_mtu(ifp->name, MTU_MIN) == -1)
446                {
447                        syslog(LOG_ERR, "%s: set_mtu: %m", p);
448                        free_interface(ifp);
449                        continue;
450                }
451
452                /* We reserve the 100 range for virtual interfaces, if and when
453                 * we can work them out. */
454                ifp->metric = 200 + ifp->index;
455                if (getifssid(ifp->name, ifp->ssid) != -1) {
456                        ifp->wireless = 1;
457                        ifp->metric += 100;
458                }
459
460                TAILQ_INSERT_TAIL(ifs, ifp, next);
461        }
462
463        for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
464                if (ifa->ifa_addr == NULL)
465                        continue;
466                switch(ifa->ifa_addr->sa_family) {
467#ifdef INET
468                case AF_INET:
469                        addr = (const struct sockaddr_in *)
470                            (void *)ifa->ifa_addr;
471                        net = (const struct sockaddr_in *)
472                            (void *)ifa->ifa_netmask;
473                        if (ifa->ifa_flags & IFF_POINTOPOINT)
474                                dst = (const struct sockaddr_in *)
475                                    (void *)ifa->ifa_dstaddr;
476                        else
477                                dst = NULL;
478                        ipv4_handleifa(RTM_NEWADDR, ifs, ifa->ifa_name,
479                                &addr->sin_addr,
480                                &net->sin_addr,
481                                dst ? &dst->sin_addr : NULL);
482                        break;
483#endif
484#ifdef INET6
485                case AF_INET6:
486                        sin6 = (const struct sockaddr_in6 *)
487                            (void *)ifa->ifa_addr;
488                        ifa_flags = in6_addr_flags(ifa->ifa_name,
489                            &sin6->sin6_addr);
490                        if (ifa_flags != -1)
491                                ipv6_handleifa(RTM_NEWADDR, ifs,
492                                    ifa->ifa_name,
493                                    &sin6->sin6_addr, ifa_flags);
494                        break;
495#endif
496                }
497        }
498
499        freeifaddrs(ifaddrs);
500
501#ifdef IFLR_ACTIVE
502        close(socket_aflink);
503#endif
504
505        return ifs;
506}
507
508int
509do_mtu(const char *ifname, short int mtu)
510{
511        struct ifreq ifr;
512        int r;
513
514        memset(&ifr, 0, sizeof(ifr));
515        strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
516        ifr.ifr_mtu = mtu;
517        r = ioctl(socket_afnet, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
518        if (r == -1)
519                return -1;
520        return ifr.ifr_mtu;
521}
Note: See TracBrowser for help on using the repository browser.