Annotation of embedaddon/dhcp/relay/dhcrelay.c, revision 1.1

1.1     ! misho       1: /* dhcrelay.c
        !             2: 
        !             3:    DHCP/BOOTP Relay Agent. */
        !             4: 
        !             5: /*
        !             6:  * Copyright(c) 2004-2011 by Internet Systems Consortium, Inc.("ISC")
        !             7:  * Copyright(c) 1997-2003 by Internet Software Consortium
        !             8:  *
        !             9:  * Permission to use, copy, modify, and distribute this software for any
        !            10:  * purpose with or without fee is hereby granted, provided that the above
        !            11:  * copyright notice and this permission notice appear in all copies.
        !            12:  *
        !            13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
        !            14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
        !            16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
        !            19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            20:  *
        !            21:  *   Internet Systems Consortium, Inc.
        !            22:  *   950 Charter Street
        !            23:  *   Redwood City, CA 94063
        !            24:  *   <info@isc.org>
        !            25:  *   https://www.isc.org/
        !            26:  *
        !            27:  * This software has been written for Internet Systems Consortium
        !            28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
        !            29:  * To learn more about Internet Systems Consortium, see
        !            30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
        !            31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
        !            32:  * ``http://www.nominum.com''.
        !            33:  */
        !            34: 
        !            35: #include "dhcpd.h"
        !            36: #include <syslog.h>
        !            37: #include <sys/time.h>
        !            38: #include <signal.h>
        !            39: 
        !            40: TIME default_lease_time = 43200; /* 12 hours... */
        !            41: TIME max_lease_time = 86400; /* 24 hours... */
        !            42: struct tree_cache *global_options[256];
        !            43: 
        !            44: struct option *requested_opts[2];
        !            45: 
        !            46: /* Needed to prevent linking against conflex.c. */
        !            47: int lexline;
        !            48: int lexchar;
        !            49: char *token_line;
        !            50: char *tlname;
        !            51: 
        !            52: const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID;
        !            53: isc_boolean_t no_dhcrelay_pid = ISC_FALSE;
        !            54: /* False (default) => we write and use a pid file */
        !            55: isc_boolean_t no_pid_file = ISC_FALSE;
        !            56: 
        !            57: int bogus_agent_drops = 0;     /* Packets dropped because agent option
        !            58:                                   field was specified and we're not relaying
        !            59:                                   packets that already have an agent option
        !            60:                                   specified. */
        !            61: int bogus_giaddr_drops = 0;    /* Packets sent to us to relay back to a
        !            62:                                   client, but with a bogus giaddr. */
        !            63: int client_packets_relayed = 0;        /* Packets relayed from client to server. */
        !            64: int server_packet_errors = 0;  /* Errors sending packets to servers. */
        !            65: int server_packets_relayed = 0;        /* Packets relayed from server to client. */
        !            66: int client_packet_errors = 0;  /* Errors sending packets to clients. */
        !            67: 
        !            68: int add_agent_options = 0;     /* If nonzero, add relay agent options. */
        !            69: 
        !            70: int agent_option_errors = 0;    /* Number of packets forwarded without
        !            71:                                   agent options because there was no room. */
        !            72: int drop_agent_mismatches = 0; /* If nonzero, drop server replies that
        !            73:                                   don't have matching circuit-id's. */
        !            74: int corrupt_agent_options = 0; /* Number of packets dropped because
        !            75:                                   relay agent information option was bad. */
        !            76: int missing_agent_option = 0;  /* Number of packets dropped because no
        !            77:                                   RAI option matching our ID was found. */
        !            78: int bad_circuit_id = 0;                /* Circuit ID option in matching RAI option
        !            79:                                   did not match any known circuit ID. */
        !            80: int missing_circuit_id = 0;    /* Circuit ID option in matching RAI option
        !            81:                                   was missing. */
        !            82: int max_hop_count = 10;                /* Maximum hop count */
        !            83: 
        !            84: #ifdef DHCPv6
        !            85:        /* Force use of DHCPv6 interface-id option. */
        !            86: isc_boolean_t use_if_id = ISC_FALSE;
        !            87: #endif
        !            88: 
        !            89:        /* Maximum size of a packet with agent options added. */
        !            90: int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN;
        !            91: 
        !            92:        /* What to do about packets we're asked to relay that
        !            93:           already have a relay option: */
        !            94: enum { forward_and_append,     /* Forward and append our own relay option. */
        !            95:        forward_and_replace,    /* Forward, but replace theirs with ours. */
        !            96:        forward_untouched,      /* Forward without changes. */
        !            97:        discard } agent_relay_mode = forward_and_replace;
        !            98: 
        !            99: u_int16_t local_port;
        !           100: u_int16_t remote_port;
        !           101: 
        !           102: /* Relay agent server list. */
        !           103: struct server_list {
        !           104:        struct server_list *next;
        !           105:        struct sockaddr_in to;
        !           106: } *servers;
        !           107: 
        !           108: #ifdef DHCPv6
        !           109: struct stream_list {
        !           110:        struct stream_list *next;
        !           111:        struct interface_info *ifp;
        !           112:        struct sockaddr_in6 link;
        !           113:        int id;
        !           114: } *downstreams, *upstreams;
        !           115: 
        !           116: static struct stream_list *parse_downstream(char *);
        !           117: static struct stream_list *parse_upstream(char *);
        !           118: static void setup_streams(void);
        !           119: #endif
        !           120: 
        !           121: static void do_relay4(struct interface_info *, struct dhcp_packet *,
        !           122:                      unsigned int, unsigned int, struct iaddr,
        !           123:                      struct hardware *);
        !           124: static int add_relay_agent_options(struct interface_info *,
        !           125:                                   struct dhcp_packet *, unsigned,
        !           126:                                   struct in_addr);
        !           127: static int find_interface_by_agent_option(struct dhcp_packet *,
        !           128:                               struct interface_info **, u_int8_t *, int);
        !           129: static int strip_relay_agent_options(struct interface_info *,
        !           130:                                     struct interface_info **,
        !           131:                                     struct dhcp_packet *, unsigned);
        !           132: 
        !           133: static const char copyright[] =
        !           134: "Copyright 2004-2011 Internet Systems Consortium.";
        !           135: static const char arr[] = "All rights reserved.";
        !           136: static const char message[] =
        !           137: "Internet Systems Consortium DHCP Relay Agent";
        !           138: static const char url[] =
        !           139: "For info, please visit https://www.isc.org/software/dhcp/";
        !           140: 
        !           141: #ifdef DHCPv6
        !           142: #define DHCRELAY_USAGE \
        !           143: "Usage: dhcrelay [-4] [-d] [-q] [-a] [-D]\n"\
        !           144: "                     [-A <length>] [-c <hops>] [-p <port>]\n" \
        !           145: "                     [-pf <pid-file>] [--no-pid]\n"\
        !           146: "                     [-m append|replace|forward|discard]\n" \
        !           147: "                     [-i interface0 [ ... -i interfaceN]\n" \
        !           148: "                     server0 [ ... serverN]\n\n" \
        !           149: "       dhcrelay -6   [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
        !           150: "                     [-pf <pid-file>] [--no-pid]\n"\
        !           151: "                     -l lower0 [ ... -l lowerN]\n" \
        !           152: "                     -u upper0 [ ... -u upperN]\n" \
        !           153: "       lower (client link): [address%%]interface[#index]\n" \
        !           154: "       upper (server link): [address%%]interface"
        !           155: #else
        !           156: #define DHCRELAY_USAGE \
        !           157: "Usage: dhcrelay [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
        !           158: "                [-pf <pid-file>] [--no-pid]\n"\
        !           159: "                [-m append|replace|forward|discard]\n" \
        !           160: "                [-i interface0 [ ... -i interfaceN]\n" \
        !           161: "                server0 [ ... serverN]\n\n"
        !           162: #endif
        !           163: 
        !           164: static void usage() {
        !           165:        log_fatal(DHCRELAY_USAGE);
        !           166: }
        !           167: 
        !           168: int 
        !           169: main(int argc, char **argv) {
        !           170:        isc_result_t status;
        !           171:        struct servent *ent;
        !           172:        struct server_list *sp = NULL;
        !           173:        struct interface_info *tmp = NULL;
        !           174:        char *service_local = NULL, *service_remote = NULL;
        !           175:        u_int16_t port_local = 0, port_remote = 0;
        !           176:        int no_daemon = 0, quiet = 0;
        !           177:        int fd;
        !           178:        int i;
        !           179: #ifdef DHCPv6
        !           180:        struct stream_list *sl = NULL;
        !           181:        int local_family_set = 0;
        !           182: #endif
        !           183: 
        !           184:        /* Make sure that file descriptors 0(stdin), 1,(stdout), and
        !           185:           2(stderr) are open. To do this, we assume that when we
        !           186:           open a file the lowest available file descriptor is used. */
        !           187:        fd = open("/dev/null", O_RDWR);
        !           188:        if (fd == 0)
        !           189:                fd = open("/dev/null", O_RDWR);
        !           190:        if (fd == 1)
        !           191:                fd = open("/dev/null", O_RDWR);
        !           192:        if (fd == 2)
        !           193:                log_perror = 0; /* No sense logging to /dev/null. */
        !           194:        else if (fd != -1)
        !           195:                close(fd);
        !           196: 
        !           197:        openlog("dhcrelay", LOG_NDELAY, LOG_DAEMON);
        !           198: 
        !           199: #if !defined(DEBUG)
        !           200:        setlogmask(LOG_UPTO(LOG_INFO));
        !           201: #endif 
        !           202: 
        !           203:        /*
        !           204:         * Set up the signal handlers, currently we only
        !           205:         * have one to ignore sigpipe.
        !           206:         */
        !           207:        if (dhcp_handle_signal(SIGPIPE, SIG_IGN) != ISC_R_SUCCESS) {
        !           208:                log_fatal("Can't set up signal handler");
        !           209:        }
        !           210: 
        !           211:        /* Set up the OMAPI. */
        !           212:        status = omapi_init();
        !           213:        if (status != ISC_R_SUCCESS)
        !           214:                log_fatal("Can't initialize OMAPI: %s",
        !           215:                           isc_result_totext(status));
        !           216: 
        !           217:        /* Set up the OMAPI wrappers for the interface object. */
        !           218:        interface_setup();
        !           219: 
        !           220:        for (i = 1; i < argc; i++) {
        !           221:                if (!strcmp(argv[i], "-4")) {
        !           222: #ifdef DHCPv6
        !           223:                        if (local_family_set && (local_family == AF_INET6)) {
        !           224:                                usage();
        !           225:                        }
        !           226:                        local_family_set = 1;
        !           227:                        local_family = AF_INET;
        !           228:                } else if (!strcmp(argv[i], "-6")) {
        !           229:                        if (local_family_set && (local_family == AF_INET)) {
        !           230:                                usage();
        !           231:                        }
        !           232:                        local_family_set = 1;
        !           233:                        local_family = AF_INET6;
        !           234: #endif
        !           235:                } else if (!strcmp(argv[i], "-d")) {
        !           236:                        no_daemon = 1;
        !           237:                } else if (!strcmp(argv[i], "-q")) {
        !           238:                        quiet = 1;
        !           239:                        quiet_interface_discovery = 1;
        !           240:                } else if (!strcmp(argv[i], "-p")) {
        !           241:                        if (++i == argc)
        !           242:                                usage();
        !           243:                        local_port = validate_port(argv[i]);
        !           244:                        log_debug("binding to user-specified port %d",
        !           245:                                  ntohs(local_port));
        !           246:                } else if (!strcmp(argv[i], "-c")) {
        !           247:                        int hcount;
        !           248:                        if (++i == argc)
        !           249:                                usage();
        !           250:                        hcount = atoi(argv[i]);
        !           251:                        if (hcount <= 255)
        !           252:                                max_hop_count= hcount;
        !           253:                        else
        !           254:                                usage();
        !           255:                } else if (!strcmp(argv[i], "-i")) {
        !           256: #ifdef DHCPv6
        !           257:                        if (local_family_set && (local_family == AF_INET6)) {
        !           258:                                usage();
        !           259:                        }
        !           260:                        local_family_set = 1;
        !           261:                        local_family = AF_INET;
        !           262: #endif
        !           263:                        status = interface_allocate(&tmp, MDL);
        !           264:                        if (status != ISC_R_SUCCESS)
        !           265:                                log_fatal("%s: interface_allocate: %s",
        !           266:                                          argv[i],
        !           267:                                          isc_result_totext(status));
        !           268:                        if (++i == argc) {
        !           269:                                usage();
        !           270:                        }
        !           271:                        strcpy(tmp->name, argv[i]);
        !           272:                        interface_snorf(tmp, INTERFACE_REQUESTED);
        !           273:                        interface_dereference(&tmp, MDL);
        !           274:                } else if (!strcmp(argv[i], "-a")) {
        !           275: #ifdef DHCPv6
        !           276:                        if (local_family_set && (local_family == AF_INET6)) {
        !           277:                                usage();
        !           278:                        }
        !           279:                        local_family_set = 1;
        !           280:                        local_family = AF_INET;
        !           281: #endif
        !           282:                        add_agent_options = 1;
        !           283:                } else if (!strcmp(argv[i], "-A")) {
        !           284: #ifdef DHCPv6
        !           285:                        if (local_family_set && (local_family == AF_INET6)) {
        !           286:                                usage();
        !           287:                        }
        !           288:                        local_family_set = 1;
        !           289:                        local_family = AF_INET;
        !           290: #endif
        !           291:                        if (++i == argc)
        !           292:                                usage();
        !           293: 
        !           294:                        dhcp_max_agent_option_packet_length = atoi(argv[i]);
        !           295: 
        !           296:                        if (dhcp_max_agent_option_packet_length > DHCP_MTU_MAX)
        !           297:                                log_fatal("%s: packet length exceeds "
        !           298:                                          "longest possible MTU\n",
        !           299:                                          argv[i]);
        !           300:                } else if (!strcmp(argv[i], "-m")) {
        !           301: #ifdef DHCPv6
        !           302:                        if (local_family_set && (local_family == AF_INET6)) {
        !           303:                                usage();
        !           304:                        }
        !           305:                        local_family_set = 1;
        !           306:                        local_family = AF_INET;
        !           307: #endif
        !           308:                        if (++i == argc)
        !           309:                                usage();
        !           310:                        if (!strcasecmp(argv[i], "append")) {
        !           311:                                agent_relay_mode = forward_and_append;
        !           312:                        } else if (!strcasecmp(argv[i], "replace")) {
        !           313:                                agent_relay_mode = forward_and_replace;
        !           314:                        } else if (!strcasecmp(argv[i], "forward")) {
        !           315:                                agent_relay_mode = forward_untouched;
        !           316:                        } else if (!strcasecmp(argv[i], "discard")) {
        !           317:                                agent_relay_mode = discard;
        !           318:                        } else
        !           319:                                usage();
        !           320:                } else if (!strcmp(argv[i], "-D")) {
        !           321: #ifdef DHCPv6
        !           322:                        if (local_family_set && (local_family == AF_INET6)) {
        !           323:                                usage();
        !           324:                        }
        !           325:                        local_family_set = 1;
        !           326:                        local_family = AF_INET;
        !           327: #endif
        !           328:                        drop_agent_mismatches = 1;
        !           329: #ifdef DHCPv6
        !           330:                } else if (!strcmp(argv[i], "-I")) {
        !           331:                        if (local_family_set && (local_family == AF_INET)) {
        !           332:                                usage();
        !           333:                        }
        !           334:                        local_family_set = 1;
        !           335:                        local_family = AF_INET6;
        !           336:                        use_if_id = ISC_TRUE;
        !           337:                } else if (!strcmp(argv[i], "-l")) {
        !           338:                        if (local_family_set && (local_family == AF_INET)) {
        !           339:                                usage();
        !           340:                        }
        !           341:                        local_family_set = 1;
        !           342:                        local_family = AF_INET6;
        !           343:                        if (downstreams != NULL)
        !           344:                                use_if_id = ISC_TRUE;
        !           345:                        if (++i == argc)
        !           346:                                usage();
        !           347:                        sl = parse_downstream(argv[i]);
        !           348:                        sl->next = downstreams;
        !           349:                        downstreams = sl;
        !           350:                } else if (!strcmp(argv[i], "-u")) {
        !           351:                        if (local_family_set && (local_family == AF_INET)) {
        !           352:                                usage();
        !           353:                        }
        !           354:                        local_family_set = 1;
        !           355:                        local_family = AF_INET6;
        !           356:                        if (++i == argc)
        !           357:                                usage();
        !           358:                        sl = parse_upstream(argv[i]);
        !           359:                        sl->next = upstreams;
        !           360:                        upstreams = sl;
        !           361: #endif
        !           362:                } else if (!strcmp(argv[i], "-pf")) {
        !           363:                        if (++i == argc)
        !           364:                                usage();
        !           365:                        path_dhcrelay_pid = argv[i];
        !           366:                        no_dhcrelay_pid = ISC_TRUE;
        !           367:                } else if (!strcmp(argv[i], "--no-pid")) {
        !           368:                        no_pid_file = ISC_TRUE;
        !           369:                } else if (!strcmp(argv[i], "--version")) {
        !           370:                        log_info("isc-dhcrelay-%s", PACKAGE_VERSION);
        !           371:                        exit(0);
        !           372:                } else if (!strcmp(argv[i], "--help") ||
        !           373:                           !strcmp(argv[i], "-h")) {
        !           374:                        log_info(DHCRELAY_USAGE);
        !           375:                        exit(0);
        !           376:                } else if (argv[i][0] == '-') {
        !           377:                        usage();
        !           378:                } else {
        !           379:                        struct hostent *he;
        !           380:                        struct in_addr ia, *iap = NULL;
        !           381: 
        !           382: #ifdef DHCPv6
        !           383:                        if (local_family_set && (local_family == AF_INET6)) {
        !           384:                                usage();
        !           385:                        }
        !           386:                        local_family_set = 1;
        !           387:                        local_family = AF_INET;
        !           388: #endif
        !           389:                        if (inet_aton(argv[i], &ia)) {
        !           390:                                iap = &ia;
        !           391:                        } else {
        !           392:                                he = gethostbyname(argv[i]);
        !           393:                                if (!he) {
        !           394:                                        log_error("%s: host unknown", argv[i]);
        !           395:                                } else {
        !           396:                                        iap = ((struct in_addr *)
        !           397:                                               he->h_addr_list[0]);
        !           398:                                }
        !           399:                        }
        !           400: 
        !           401:                        if (iap) {
        !           402:                                sp = ((struct server_list *)
        !           403:                                      dmalloc(sizeof *sp, MDL));
        !           404:                                if (!sp)
        !           405:                                        log_fatal("no memory for server.\n");
        !           406:                                sp->next = servers;
        !           407:                                servers = sp;
        !           408:                                memcpy(&sp->to.sin_addr, iap, sizeof *iap);
        !           409:                        }
        !           410:                }
        !           411:        }
        !           412: 
        !           413:        /*
        !           414:         * If the user didn't specify a pid file directly
        !           415:         * find one from environment variables or defaults
        !           416:         */
        !           417:        if (no_dhcrelay_pid == ISC_FALSE) {
        !           418:                if (local_family == AF_INET) {
        !           419:                        path_dhcrelay_pid = getenv("PATH_DHCRELAY_PID");
        !           420:                        if (path_dhcrelay_pid == NULL)
        !           421:                                path_dhcrelay_pid = _PATH_DHCRELAY_PID;
        !           422:                }
        !           423: #ifdef DHCPv6
        !           424:                else {
        !           425:                        path_dhcrelay_pid = getenv("PATH_DHCRELAY6_PID");
        !           426:                        if (path_dhcrelay_pid == NULL)
        !           427:                                path_dhcrelay_pid = _PATH_DHCRELAY6_PID;
        !           428:                }
        !           429: #endif
        !           430:        }
        !           431: 
        !           432:        if (!quiet) {
        !           433:                log_info("%s %s", message, PACKAGE_VERSION);
        !           434:                log_info(copyright);
        !           435:                log_info(arr);
        !           436:                log_info(url);
        !           437:        } else {
        !           438:                quiet = 0;
        !           439:                log_perror = 0;
        !           440:        }
        !           441: 
        !           442:        /* Set default port */
        !           443:        if (local_family == AF_INET) {
        !           444:                service_local = "bootps";
        !           445:                service_remote = "bootpc";
        !           446:                port_local = htons(67);
        !           447:                port_remote = htons(68);
        !           448:        }
        !           449: #ifdef DHCPv6
        !           450:        else {
        !           451:                service_local = "dhcpv6-server";
        !           452:                service_remote = "dhcpv6-client";
        !           453:                port_local = htons(547);
        !           454:                port_remote = htons(546);
        !           455:        }
        !           456: #endif
        !           457: 
        !           458:        if (!local_port) {
        !           459:                ent = getservbyname(service_local, "udp");
        !           460:                if (ent)
        !           461:                        local_port = ent->s_port;
        !           462:                else
        !           463:                        local_port = port_local;
        !           464: 
        !           465:                ent = getservbyname(service_remote, "udp");
        !           466:                if (ent)
        !           467:                        remote_port = ent->s_port;
        !           468:                else
        !           469:                        remote_port = port_remote;
        !           470: 
        !           471:                endservent();
        !           472:        }
        !           473: 
        !           474:        if (local_family == AF_INET) {
        !           475:                /* We need at least one server */
        !           476:                if (servers == NULL) {
        !           477:                        log_fatal("No servers specified.");
        !           478:                }
        !           479: 
        !           480: 
        !           481:                /* Set up the server sockaddrs. */
        !           482:                for (sp = servers; sp; sp = sp->next) {
        !           483:                        sp->to.sin_port = local_port;
        !           484:                        sp->to.sin_family = AF_INET;
        !           485: #ifdef HAVE_SA_LEN
        !           486:                        sp->to.sin_len = sizeof sp->to;
        !           487: #endif
        !           488:                }
        !           489:        }
        !           490: #ifdef DHCPv6
        !           491:        else {
        !           492:                unsigned code;
        !           493: 
        !           494:                /* We need at least one upstream and one downstream interface */
        !           495:                if (upstreams == NULL || downstreams == NULL) {
        !           496:                        log_info("Must specify at least one lower "
        !           497:                                 "and one upper interface.\n");
        !           498:                        usage();
        !           499:                }
        !           500: 
        !           501:                /* Set up the initial dhcp option universe. */
        !           502:                initialize_common_option_spaces();
        !           503: 
        !           504:                /* Check requested options. */
        !           505:                code = D6O_RELAY_MSG;
        !           506:                if (!option_code_hash_lookup(&requested_opts[0],
        !           507:                                             dhcpv6_universe.code_hash,
        !           508:                                             &code, 0, MDL))
        !           509:                        log_fatal("Unable to find the RELAY_MSG "
        !           510:                                  "option definition.");
        !           511:                code = D6O_INTERFACE_ID;
        !           512:                if (!option_code_hash_lookup(&requested_opts[1],
        !           513:                                             dhcpv6_universe.code_hash,
        !           514:                                             &code, 0, MDL))
        !           515:                        log_fatal("Unable to find the INTERFACE_ID "
        !           516:                                  "option definition.");
        !           517:        }
        !           518: #endif
        !           519: 
        !           520:        /* Get the current time... */
        !           521:        gettimeofday(&cur_tv, NULL);
        !           522: 
        !           523:        /* Discover all the network interfaces. */
        !           524:        discover_interfaces(DISCOVER_RELAY);
        !           525: 
        !           526: #ifdef DHCPv6
        !           527:        if (local_family == AF_INET6)
        !           528:                setup_streams();
        !           529: #endif
        !           530: 
        !           531:        /* Become a daemon... */
        !           532:        if (!no_daemon) {
        !           533:                int pid;
        !           534:                FILE *pf;
        !           535:                int pfdesc;
        !           536: 
        !           537:                log_perror = 0;
        !           538: 
        !           539:                if ((pid = fork()) < 0)
        !           540:                        log_fatal("Can't fork daemon: %m");
        !           541:                else if (pid)
        !           542:                        exit(0);
        !           543: 
        !           544:                if (no_pid_file == ISC_FALSE) {
        !           545:                        pfdesc = open(path_dhcrelay_pid,
        !           546:                                      O_CREAT | O_TRUNC | O_WRONLY, 0644);
        !           547: 
        !           548:                        if (pfdesc < 0) {
        !           549:                                log_error("Can't create %s: %m",
        !           550:                                          path_dhcrelay_pid);
        !           551:                        } else {
        !           552:                                pf = fdopen(pfdesc, "w");
        !           553:                                if (!pf)
        !           554:                                        log_error("Can't fdopen %s: %m",
        !           555:                                                  path_dhcrelay_pid);
        !           556:                                else {
        !           557:                                        fprintf(pf, "%ld\n",(long)getpid());
        !           558:                                        fclose(pf);
        !           559:                                }       
        !           560:                        }
        !           561:                }
        !           562: 
        !           563:                close(0);
        !           564:                close(1);
        !           565:                close(2);
        !           566:                pid = setsid();
        !           567: 
        !           568:                IGNORE_RET (chdir("/"));
        !           569:        }
        !           570: 
        !           571:        /* Set up the packet handler... */
        !           572:        if (local_family == AF_INET)
        !           573:                bootp_packet_handler = do_relay4;
        !           574: #ifdef DHCPv6
        !           575:        else
        !           576:                dhcpv6_packet_handler = do_packet6;
        !           577: #endif
        !           578: 
        !           579:        /* Start dispatching packets and timeouts... */
        !           580:        dispatch();
        !           581: 
        !           582:        /* Not reached */
        !           583:        return (0);
        !           584: }
        !           585: 
        !           586: static void
        !           587: do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
        !           588:          unsigned int length, unsigned int from_port, struct iaddr from,
        !           589:          struct hardware *hfrom) {
        !           590:        struct server_list *sp;
        !           591:        struct sockaddr_in to;
        !           592:        struct interface_info *out;
        !           593:        struct hardware hto, *htop;
        !           594: 
        !           595:        if (packet->hlen > sizeof packet->chaddr) {
        !           596:                log_info("Discarding packet with invalid hlen.");
        !           597:                return;
        !           598:        }
        !           599: 
        !           600:        if (ip->address_count < 1 || ip->addresses == NULL) {
        !           601:                log_info("Discarding packet received on %s interface that "
        !           602:                         "has no IPv4 address assigned.", ip->name);
        !           603:                return;
        !           604:        }
        !           605: 
        !           606:        /* Find the interface that corresponds to the giaddr
        !           607:           in the packet. */
        !           608:        if (packet->giaddr.s_addr) {
        !           609:                for (out = interfaces; out; out = out->next) {
        !           610:                        int i;
        !           611: 
        !           612:                        for (i = 0 ; i < out->address_count ; i++ ) {
        !           613:                                if (out->addresses[i].s_addr ==
        !           614:                                    packet->giaddr.s_addr)
        !           615:                                        i = -1;
        !           616:                                        break;
        !           617:                        }
        !           618: 
        !           619:                        if (i == -1)
        !           620:                                break;
        !           621:                }
        !           622:        } else {
        !           623:                out = NULL;
        !           624:        }
        !           625: 
        !           626:        /* If it's a bootreply, forward it to the client. */
        !           627:        if (packet->op == BOOTREPLY) {
        !           628:                if (!(packet->flags & htons(BOOTP_BROADCAST)) &&
        !           629:                        can_unicast_without_arp(out)) {
        !           630:                        to.sin_addr = packet->yiaddr;
        !           631:                        to.sin_port = remote_port;
        !           632: 
        !           633:                        /* and hardware address is not broadcast */
        !           634:                        htop = &hto;
        !           635:                } else {
        !           636:                        to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
        !           637:                        to.sin_port = remote_port;
        !           638: 
        !           639:                        /* hardware address is broadcast */
        !           640:                        htop = NULL;
        !           641:                }
        !           642:                to.sin_family = AF_INET;
        !           643: #ifdef HAVE_SA_LEN
        !           644:                to.sin_len = sizeof to;
        !           645: #endif
        !           646: 
        !           647:                memcpy(&hto.hbuf[1], packet->chaddr, packet->hlen);
        !           648:                hto.hbuf[0] = packet->htype;
        !           649:                hto.hlen = packet->hlen + 1;
        !           650: 
        !           651:                /* Wipe out the agent relay options and, if possible, figure
        !           652:                   out which interface to use based on the contents of the
        !           653:                   option that we put on the request to which the server is
        !           654:                   replying. */
        !           655:                if (!(length =
        !           656:                      strip_relay_agent_options(ip, &out, packet, length)))
        !           657:                        return;
        !           658: 
        !           659:                if (!out) {
        !           660:                        log_error("Packet to bogus giaddr %s.\n",
        !           661:                              inet_ntoa(packet->giaddr));
        !           662:                        ++bogus_giaddr_drops;
        !           663:                        return;
        !           664:                }
        !           665: 
        !           666:                if (send_packet(out, NULL, packet, length, out->addresses[0],
        !           667:                                &to, htop) < 0) {
        !           668:                        ++server_packet_errors;
        !           669:                } else {
        !           670:                        log_debug("Forwarded BOOTREPLY for %s to %s",
        !           671:                               print_hw_addr(packet->htype, packet->hlen,
        !           672:                                              packet->chaddr),
        !           673:                               inet_ntoa(to.sin_addr));
        !           674: 
        !           675:                        ++server_packets_relayed;
        !           676:                }
        !           677:                return;
        !           678:        }
        !           679: 
        !           680:        /* If giaddr matches one of our addresses, ignore the packet -
        !           681:           we just sent it. */
        !           682:        if (out)
        !           683:                return;
        !           684: 
        !           685:        /* Add relay agent options if indicated.   If something goes wrong,
        !           686:           drop the packet. */
        !           687:        if (!(length = add_relay_agent_options(ip, packet, length,
        !           688:                                               ip->addresses[0])))
        !           689:                return;
        !           690: 
        !           691:        /* If giaddr is not already set, Set it so the server can
        !           692:           figure out what net it's from and so that we can later
        !           693:           forward the response to the correct net.    If it's already
        !           694:           set, the response will be sent directly to the relay agent
        !           695:           that set giaddr, so we won't see it. */
        !           696:        if (!packet->giaddr.s_addr)
        !           697:                packet->giaddr = ip->addresses[0];
        !           698:        if (packet->hops < max_hop_count)
        !           699:                packet->hops = packet->hops + 1;
        !           700:        else
        !           701:                return;
        !           702: 
        !           703:        /* Otherwise, it's a BOOTREQUEST, so forward it to all the
        !           704:           servers. */
        !           705:        for (sp = servers; sp; sp = sp->next) {
        !           706:                if (send_packet((fallback_interface
        !           707:                                 ? fallback_interface : interfaces),
        !           708:                                 NULL, packet, length, ip->addresses[0],
        !           709:                                 &sp->to, NULL) < 0) {
        !           710:                        ++client_packet_errors;
        !           711:                } else {
        !           712:                        log_debug("Forwarded BOOTREQUEST for %s to %s",
        !           713:                               print_hw_addr(packet->htype, packet->hlen,
        !           714:                                              packet->chaddr),
        !           715:                               inet_ntoa(sp->to.sin_addr));
        !           716:                        ++client_packets_relayed;
        !           717:                }
        !           718:        }
        !           719:                                 
        !           720: }
        !           721: 
        !           722: /* Strip any Relay Agent Information options from the DHCP packet
        !           723:    option buffer.   If there is a circuit ID suboption, look up the
        !           724:    outgoing interface based upon it. */
        !           725: 
        !           726: static int
        !           727: strip_relay_agent_options(struct interface_info *in,
        !           728:                          struct interface_info **out,
        !           729:                          struct dhcp_packet *packet,
        !           730:                          unsigned length) {
        !           731:        int is_dhcp = 0;
        !           732:        u_int8_t *op, *nextop, *sp, *max;
        !           733:        int good_agent_option = 0;
        !           734:        int status;
        !           735: 
        !           736:        /* If we're not adding agent options to packets, we're not taking
        !           737:           them out either. */
        !           738:        if (!add_agent_options)
        !           739:                return (length);
        !           740: 
        !           741:        /* If there's no cookie, it's a bootp packet, so we should just
        !           742:           forward it unchanged. */
        !           743:        if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
        !           744:                return (length);
        !           745: 
        !           746:        max = ((u_int8_t *)packet) + length;
        !           747:        sp = op = &packet->options[4];
        !           748: 
        !           749:        while (op < max) {
        !           750:                switch(*op) {
        !           751:                        /* Skip padding... */
        !           752:                      case DHO_PAD:
        !           753:                        if (sp != op)
        !           754:                                *sp = *op;
        !           755:                        ++op;
        !           756:                        ++sp;
        !           757:                        continue;
        !           758: 
        !           759:                        /* If we see a message type, it's a DHCP packet. */
        !           760:                      case DHO_DHCP_MESSAGE_TYPE:
        !           761:                        is_dhcp = 1;
        !           762:                        goto skip;
        !           763:                        break;
        !           764: 
        !           765:                        /* Quit immediately if we hit an End option. */
        !           766:                      case DHO_END:
        !           767:                        if (sp != op)
        !           768:                                *sp++ = *op++;
        !           769:                        goto out;
        !           770: 
        !           771:                      case DHO_DHCP_AGENT_OPTIONS:
        !           772:                        /* We shouldn't see a relay agent option in a
        !           773:                           packet before we've seen the DHCP packet type,
        !           774:                           but if we do, we have to leave it alone. */
        !           775:                        if (!is_dhcp)
        !           776:                                goto skip;
        !           777: 
        !           778:                        /* Do not process an agent option if it exceeds the
        !           779:                         * buffer.  Fail this packet.
        !           780:                         */
        !           781:                        nextop = op + op[1] + 2;
        !           782:                        if (nextop > max)
        !           783:                                return (0);
        !           784: 
        !           785:                        status = find_interface_by_agent_option(packet,
        !           786:                                                                out, op + 2,
        !           787:                                                                op[1]);
        !           788:                        if (status == -1 && drop_agent_mismatches)
        !           789:                                return (0);
        !           790:                        if (status)
        !           791:                                good_agent_option = 1;
        !           792:                        op = nextop;
        !           793:                        break;
        !           794: 
        !           795:                      skip:
        !           796:                        /* Skip over other options. */
        !           797:                      default:
        !           798:                        /* Fail if processing this option will exceed the
        !           799:                         * buffer(op[1] is malformed).
        !           800:                         */
        !           801:                        nextop = op + op[1] + 2;
        !           802:                        if (nextop > max)
        !           803:                                return (0);
        !           804: 
        !           805:                        if (sp != op) {
        !           806:                                memmove(sp, op, op[1] + 2);
        !           807:                                sp += op[1] + 2;
        !           808:                                op = nextop;
        !           809:                        } else
        !           810:                                op = sp = nextop;
        !           811: 
        !           812:                        break;
        !           813:                }
        !           814:        }
        !           815:       out:
        !           816: 
        !           817:        /* If it's not a DHCP packet, we're not supposed to touch it. */
        !           818:        if (!is_dhcp)
        !           819:                return (length);
        !           820: 
        !           821:        /* If none of the agent options we found matched, or if we didn't
        !           822:           find any agent options, count this packet as not having any
        !           823:           matching agent options, and if we're relying on agent options
        !           824:           to determine the outgoing interface, drop the packet. */
        !           825: 
        !           826:        if (!good_agent_option) {
        !           827:                ++missing_agent_option;
        !           828:                if (drop_agent_mismatches)
        !           829:                        return (0);
        !           830:        }
        !           831: 
        !           832:        /* Adjust the length... */
        !           833:        if (sp != op) {
        !           834:                length = sp -((u_int8_t *)packet);
        !           835: 
        !           836:                /* Make sure the packet isn't short(this is unlikely,
        !           837:                   but WTH) */
        !           838:                if (length < BOOTP_MIN_LEN) {
        !           839:                        memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
        !           840:                        length = BOOTP_MIN_LEN;
        !           841:                }
        !           842:        }
        !           843:        return (length);
        !           844: }
        !           845: 
        !           846: 
        !           847: /* Find an interface that matches the circuit ID specified in the
        !           848:    Relay Agent Information option.   If one is found, store it through
        !           849:    the pointer given; otherwise, leave the existing pointer alone.
        !           850: 
        !           851:    We actually deviate somewhat from the current specification here:
        !           852:    if the option buffer is corrupt, we suggest that the caller not
        !           853:    respond to this packet.  If the circuit ID doesn't match any known
        !           854:    interface, we suggest that the caller to drop the packet.  Only if
        !           855:    we find a circuit ID that matches an existing interface do we tell
        !           856:    the caller to go ahead and process the packet. */
        !           857: 
        !           858: static int
        !           859: find_interface_by_agent_option(struct dhcp_packet *packet,
        !           860:                               struct interface_info **out,
        !           861:                               u_int8_t *buf, int len) {
        !           862:        int i = 0;
        !           863:        u_int8_t *circuit_id = 0;
        !           864:        unsigned circuit_id_len = 0;
        !           865:        struct interface_info *ip;
        !           866: 
        !           867:        while (i < len) {
        !           868:                /* If the next agent option overflows the end of the
        !           869:                   packet, the agent option buffer is corrupt. */
        !           870:                if (i + 1 == len ||
        !           871:                    i + buf[i + 1] + 2 > len) {
        !           872:                        ++corrupt_agent_options;
        !           873:                        return (-1);
        !           874:                }
        !           875:                switch(buf[i]) {
        !           876:                        /* Remember where the circuit ID is... */
        !           877:                      case RAI_CIRCUIT_ID:
        !           878:                        circuit_id = &buf[i + 2];
        !           879:                        circuit_id_len = buf[i + 1];
        !           880:                        i += circuit_id_len + 2;
        !           881:                        continue;
        !           882: 
        !           883:                      default:
        !           884:                        i += buf[i + 1] + 2;
        !           885:                        break;
        !           886:                }
        !           887:        }
        !           888: 
        !           889:        /* If there's no circuit ID, it's not really ours, tell the caller
        !           890:           it's no good. */
        !           891:        if (!circuit_id) {
        !           892:                ++missing_circuit_id;
        !           893:                return (-1);
        !           894:        }
        !           895: 
        !           896:        /* Scan the interface list looking for an interface whose
        !           897:           name matches the one specified in circuit_id. */
        !           898: 
        !           899:        for (ip = interfaces; ip; ip = ip->next) {
        !           900:                if (ip->circuit_id &&
        !           901:                    ip->circuit_id_len == circuit_id_len &&
        !           902:                    !memcmp(ip->circuit_id, circuit_id, circuit_id_len))
        !           903:                        break;
        !           904:        }
        !           905: 
        !           906:        /* If we got a match, use it. */
        !           907:        if (ip) {
        !           908:                *out = ip;
        !           909:                return (1);
        !           910:        }
        !           911: 
        !           912:        /* If we didn't get a match, the circuit ID was bogus. */
        !           913:        ++bad_circuit_id;
        !           914:        return (-1);
        !           915: }
        !           916: 
        !           917: /*
        !           918:  * Examine a packet to see if it's a candidate to have a Relay
        !           919:  * Agent Information option tacked onto its tail.   If it is, tack
        !           920:  * the option on.
        !           921:  */
        !           922: static int
        !           923: add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
        !           924:                        unsigned length, struct in_addr giaddr) {
        !           925:        int is_dhcp = 0, mms;
        !           926:        unsigned optlen;
        !           927:        u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
        !           928: 
        !           929:        /* If we're not adding agent options to packets, we can skip
        !           930:           this. */
        !           931:        if (!add_agent_options)
        !           932:                return (length);
        !           933: 
        !           934:        /* If there's no cookie, it's a bootp packet, so we should just
        !           935:           forward it unchanged. */
        !           936:        if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
        !           937:                return (length);
        !           938: 
        !           939:        max = ((u_int8_t *)packet) + dhcp_max_agent_option_packet_length;
        !           940: 
        !           941:        /* Commence processing after the cookie. */
        !           942:        sp = op = &packet->options[4];
        !           943: 
        !           944:        while (op < max) {
        !           945:                switch(*op) {
        !           946:                        /* Skip padding... */
        !           947:                      case DHO_PAD:
        !           948:                        /* Remember the first pad byte so we can commandeer
        !           949:                         * padded space.
        !           950:                         *
        !           951:                         * XXX: Is this really a good idea?  Sure, we can
        !           952:                         * seemingly reduce the packet while we're looking,
        !           953:                         * but if the packet was signed by the client then
        !           954:                         * this padding is part of the checksum(RFC3118),
        !           955:                         * and its nonpresence would break authentication.
        !           956:                         */
        !           957:                        if (end_pad == NULL)
        !           958:                                end_pad = sp;
        !           959: 
        !           960:                        if (sp != op)
        !           961:                                *sp++ = *op++;
        !           962:                        else
        !           963:                                sp = ++op;
        !           964: 
        !           965:                        continue;
        !           966: 
        !           967:                        /* If we see a message type, it's a DHCP packet. */
        !           968:                      case DHO_DHCP_MESSAGE_TYPE:
        !           969:                        is_dhcp = 1;
        !           970:                        goto skip;
        !           971: 
        !           972:                        /*
        !           973:                         * If there's a maximum message size option, we
        !           974:                         * should pay attention to it
        !           975:                         */
        !           976:                      case DHO_DHCP_MAX_MESSAGE_SIZE:
        !           977:                        mms = ntohs(*(op + 2));
        !           978:                        if (mms < dhcp_max_agent_option_packet_length &&
        !           979:                            mms >= DHCP_MTU_MIN)
        !           980:                                max = ((u_int8_t *)packet) + mms;
        !           981:                        goto skip;
        !           982: 
        !           983:                        /* Quit immediately if we hit an End option. */
        !           984:                      case DHO_END:
        !           985:                        goto out;
        !           986: 
        !           987:                      case DHO_DHCP_AGENT_OPTIONS:
        !           988:                        /* We shouldn't see a relay agent option in a
        !           989:                           packet before we've seen the DHCP packet type,
        !           990:                           but if we do, we have to leave it alone. */
        !           991:                        if (!is_dhcp)
        !           992:                                goto skip;
        !           993: 
        !           994:                        end_pad = NULL;
        !           995: 
        !           996:                        /* There's already a Relay Agent Information option
        !           997:                           in this packet.   How embarrassing.   Decide what
        !           998:                           to do based on the mode the user specified. */
        !           999: 
        !          1000:                        switch(agent_relay_mode) {
        !          1001:                              case forward_and_append:
        !          1002:                                goto skip;
        !          1003:                              case forward_untouched:
        !          1004:                                return (length);
        !          1005:                              case discard:
        !          1006:                                return (0);
        !          1007:                              case forward_and_replace:
        !          1008:                              default:
        !          1009:                                break;
        !          1010:                        }
        !          1011: 
        !          1012:                        /* Skip over the agent option and start copying
        !          1013:                           if we aren't copying already. */
        !          1014:                        op += op[1] + 2;
        !          1015:                        break;
        !          1016: 
        !          1017:                      skip:
        !          1018:                        /* Skip over other options. */
        !          1019:                      default:
        !          1020:                        /* Fail if processing this option will exceed the
        !          1021:                         * buffer(op[1] is malformed).
        !          1022:                         */
        !          1023:                        nextop = op + op[1] + 2;
        !          1024:                        if (nextop > max)
        !          1025:                                return (0);
        !          1026: 
        !          1027:                        end_pad = NULL;
        !          1028: 
        !          1029:                        if (sp != op) {
        !          1030:                                memmove(sp, op, op[1] + 2);
        !          1031:                                sp += op[1] + 2;
        !          1032:                                op = nextop;
        !          1033:                        } else
        !          1034:                                op = sp = nextop;
        !          1035: 
        !          1036:                        break;
        !          1037:                }
        !          1038:        }
        !          1039:       out:
        !          1040: 
        !          1041:        /* If it's not a DHCP packet, we're not supposed to touch it. */
        !          1042:        if (!is_dhcp)
        !          1043:                return (length);
        !          1044: 
        !          1045:        /* If the packet was padded out, we can store the agent option
        !          1046:           at the beginning of the padding. */
        !          1047: 
        !          1048:        if (end_pad != NULL)
        !          1049:                sp = end_pad;
        !          1050: 
        !          1051:        /* Remember where the end of the packet was after parsing
        !          1052:           it. */
        !          1053:        op = sp;
        !          1054: 
        !          1055:        /* Sanity check.  Had better not ever happen. */
        !          1056:        if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1))
        !          1057:                log_fatal("Circuit ID length %d out of range [1-255] on "
        !          1058:                          "%s\n", ip->circuit_id_len, ip->name);
        !          1059:        optlen = ip->circuit_id_len + 2;            /* RAI_CIRCUIT_ID + len */
        !          1060: 
        !          1061:        if (ip->remote_id) {
        !          1062:                if (ip->remote_id_len > 255 || ip->remote_id_len < 1)
        !          1063:                        log_fatal("Remote ID length %d out of range [1-255] "
        !          1064:                                  "on %s\n", ip->circuit_id_len, ip->name);
        !          1065:                optlen += ip->remote_id_len + 2;    /* RAI_REMOTE_ID + len */
        !          1066:        }
        !          1067: 
        !          1068:        /* We do not support relay option fragmenting(multiple options to
        !          1069:         * support an option data exceeding 255 bytes).
        !          1070:         */
        !          1071:        if ((optlen < 3) ||(optlen > 255))
        !          1072:                log_fatal("Total agent option length(%u) out of range "
        !          1073:                           "[3 - 255] on %s\n", optlen, ip->name);
        !          1074: 
        !          1075:        /*
        !          1076:         * Is there room for the option, its code+len, and DHO_END?
        !          1077:         * If not, forward without adding the option.
        !          1078:         */
        !          1079:        if (max - sp >= optlen + 3) {
        !          1080:                log_debug("Adding %d-byte relay agent option", optlen + 3);
        !          1081: 
        !          1082:                /* Okay, cons up *our* Relay Agent Information option. */
        !          1083:                *sp++ = DHO_DHCP_AGENT_OPTIONS;
        !          1084:                *sp++ = optlen;
        !          1085: 
        !          1086:                /* Copy in the circuit id... */
        !          1087:                *sp++ = RAI_CIRCUIT_ID;
        !          1088:                *sp++ = ip->circuit_id_len;
        !          1089:                memcpy(sp, ip->circuit_id, ip->circuit_id_len);
        !          1090:                sp += ip->circuit_id_len;
        !          1091: 
        !          1092:                /* Copy in remote ID... */
        !          1093:                if (ip->remote_id) {
        !          1094:                        *sp++ = RAI_REMOTE_ID;
        !          1095:                        *sp++ = ip->remote_id_len;
        !          1096:                        memcpy(sp, ip->remote_id, ip->remote_id_len);
        !          1097:                        sp += ip->remote_id_len;
        !          1098:                }
        !          1099:        } else {
        !          1100:                ++agent_option_errors;
        !          1101:                log_error("No room in packet (used %d of %d) "
        !          1102:                          "for %d-byte relay agent option: omitted",
        !          1103:                           (int) (sp - ((u_int8_t *) packet)),
        !          1104:                           (int) (max - ((u_int8_t *) packet)),
        !          1105:                           optlen + 3);
        !          1106:        }
        !          1107: 
        !          1108:        /*
        !          1109:         * Deposit an END option unless the packet is full (shouldn't
        !          1110:         * be possible).
        !          1111:         */
        !          1112:        if (sp < max)
        !          1113:                *sp++ = DHO_END;
        !          1114: 
        !          1115:        /* Recalculate total packet length. */
        !          1116:        length = sp -((u_int8_t *)packet);
        !          1117: 
        !          1118:        /* Make sure the packet isn't short(this is unlikely, but WTH) */
        !          1119:        if (length < BOOTP_MIN_LEN) {
        !          1120:                memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
        !          1121:                return (BOOTP_MIN_LEN);
        !          1122:        }
        !          1123: 
        !          1124:        return (length);
        !          1125: }
        !          1126: 
        !          1127: #ifdef DHCPv6
        !          1128: /*
        !          1129:  * Parse a downstream argument: [address%]interface[#index].
        !          1130:  */
        !          1131: static struct stream_list *
        !          1132: parse_downstream(char *arg) {
        !          1133:        struct stream_list *dp, *up;
        !          1134:        struct interface_info *ifp = NULL;
        !          1135:        char *ifname, *addr, *iid;
        !          1136:        isc_result_t status;
        !          1137: 
        !          1138:        if (!supports_multiple_interfaces(ifp) &&
        !          1139:            (downstreams != NULL))
        !          1140:                log_fatal("No support for multiple interfaces.");
        !          1141: 
        !          1142:        /* Decode the argument. */
        !          1143:        ifname = strchr(arg, '%');
        !          1144:        if (ifname == NULL) {
        !          1145:                ifname = arg;
        !          1146:                addr = NULL;
        !          1147:        } else {
        !          1148:                *ifname++ = '\0';
        !          1149:                addr = arg;
        !          1150:        }
        !          1151:        iid = strchr(ifname, '#');
        !          1152:        if (iid != NULL) {
        !          1153:                *iid++ = '\0';
        !          1154:        }
        !          1155:        if (strlen(ifname) >= sizeof(ifp->name)) {
        !          1156:                log_error("Interface name '%s' too long", ifname);
        !          1157:                usage();
        !          1158:        }
        !          1159: 
        !          1160:        /* Don't declare twice. */
        !          1161:        for (dp = downstreams; dp; dp = dp->next) {
        !          1162:                if (strcmp(ifname, dp->ifp->name) == 0)
        !          1163:                        log_fatal("Down interface '%s' declared twice.",
        !          1164:                                  ifname);
        !          1165:        }
        !          1166: 
        !          1167:        /* Share with up side? */
        !          1168:        for (up = upstreams; up; up = up->next) {
        !          1169:                if (strcmp(ifname, up->ifp->name) == 0) {
        !          1170:                        log_info("Interface '%s' is both down and up.",
        !          1171:                                 ifname);
        !          1172:                        ifp = up->ifp;
        !          1173:                        break;
        !          1174:                }
        !          1175:        }
        !          1176: 
        !          1177:        /* New interface. */
        !          1178:        if (ifp == NULL) {
        !          1179:                status = interface_allocate(&ifp, MDL);
        !          1180:                if (status != ISC_R_SUCCESS)
        !          1181:                        log_fatal("%s: interface_allocate: %s",
        !          1182:                                  arg, isc_result_totext(status));
        !          1183:                strcpy(ifp->name, ifname);
        !          1184:                if (interfaces) {
        !          1185:                        interface_reference(&ifp->next, interfaces, MDL);
        !          1186:                        interface_dereference(&interfaces, MDL);
        !          1187:                }
        !          1188:                interface_reference(&interfaces, ifp, MDL);
        !          1189:                ifp->flags |= INTERFACE_REQUESTED | INTERFACE_DOWNSTREAM;
        !          1190:        }
        !          1191: 
        !          1192:        /* New downstream. */
        !          1193:        dp = (struct stream_list *) dmalloc(sizeof(*dp), MDL);
        !          1194:        if (!dp)
        !          1195:                log_fatal("No memory for downstream.");
        !          1196:        dp->ifp = ifp;
        !          1197:        if (iid != NULL) {
        !          1198:                dp->id = atoi(iid);
        !          1199:        } else {
        !          1200:                dp->id = -1;
        !          1201:        }
        !          1202:        /* !addr case handled by setup. */
        !          1203:        if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0))
        !          1204:                log_fatal("Bad link address '%s'", addr);
        !          1205: 
        !          1206:        return dp;
        !          1207: }
        !          1208: 
        !          1209: /*
        !          1210:  * Parse an upstream argument: [address]%interface.
        !          1211:  */
        !          1212: static struct stream_list *
        !          1213: parse_upstream(char *arg) {
        !          1214:        struct stream_list *up, *dp;
        !          1215:        struct interface_info *ifp = NULL;
        !          1216:        char *ifname, *addr;
        !          1217:        isc_result_t status;
        !          1218: 
        !          1219:        /* Decode the argument. */
        !          1220:        ifname = strchr(arg, '%');
        !          1221:        if (ifname == NULL) {
        !          1222:                ifname = arg;
        !          1223:                addr = All_DHCP_Servers;
        !          1224:        } else {
        !          1225:                *ifname++ = '\0';
        !          1226:                addr = arg;
        !          1227:        }
        !          1228:        if (strlen(ifname) >= sizeof(ifp->name)) {
        !          1229:                log_fatal("Interface name '%s' too long", ifname);
        !          1230:        }
        !          1231: 
        !          1232:        /* Shared up interface? */
        !          1233:        for (up = upstreams; up; up = up->next) {
        !          1234:                if (strcmp(ifname, up->ifp->name) == 0) {
        !          1235:                        ifp = up->ifp;
        !          1236:                        break;
        !          1237:                }
        !          1238:        }
        !          1239:        for (dp = downstreams; dp; dp = dp->next) {
        !          1240:                if (strcmp(ifname, dp->ifp->name) == 0) {
        !          1241:                        ifp = dp->ifp;
        !          1242:                        break;
        !          1243:                }
        !          1244:        }
        !          1245: 
        !          1246:        /* New interface. */
        !          1247:        if (ifp == NULL) {
        !          1248:                status = interface_allocate(&ifp, MDL);
        !          1249:                if (status != ISC_R_SUCCESS)
        !          1250:                        log_fatal("%s: interface_allocate: %s",
        !          1251:                                  arg, isc_result_totext(status));
        !          1252:                strcpy(ifp->name, ifname);
        !          1253:                if (interfaces) {
        !          1254:                        interface_reference(&ifp->next, interfaces, MDL);
        !          1255:                        interface_dereference(&interfaces, MDL);
        !          1256:                }
        !          1257:                interface_reference(&interfaces, ifp, MDL);
        !          1258:                ifp->flags |= INTERFACE_REQUESTED | INTERFACE_UPSTREAM;
        !          1259:        }
        !          1260: 
        !          1261:        /* New upstream. */
        !          1262:        up = (struct stream_list *) dmalloc(sizeof(*up), MDL);
        !          1263:        if (up == NULL)
        !          1264:                log_fatal("No memory for upstream.");
        !          1265: 
        !          1266:        up->ifp = ifp;
        !          1267: 
        !          1268:        if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0)
        !          1269:                log_fatal("Bad address %s", addr);
        !          1270: 
        !          1271:        return up;
        !          1272: }
        !          1273: 
        !          1274: /*
        !          1275:  * Setup downstream interfaces.
        !          1276:  */
        !          1277: static void
        !          1278: setup_streams(void) {
        !          1279:        struct stream_list *dp, *up;
        !          1280:        int i;
        !          1281:        isc_boolean_t link_is_set;
        !          1282: 
        !          1283:        for (dp = downstreams; dp; dp = dp->next) {
        !          1284:                /* Check interface */
        !          1285:                if (dp->ifp->v6address_count == 0)
        !          1286:                        log_fatal("Interface '%s' has no IPv6 addresses.",
        !          1287:                                  dp->ifp->name);
        !          1288: 
        !          1289:                /* Check/set link. */
        !          1290:                if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr))
        !          1291:                        link_is_set = ISC_FALSE;
        !          1292:                else
        !          1293:                        link_is_set = ISC_TRUE;
        !          1294:                for (i = 0; i < dp->ifp->v6address_count; i++) {
        !          1295:                        if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i]))
        !          1296:                                continue;
        !          1297:                        if (!link_is_set)
        !          1298:                                break;
        !          1299:                        if (!memcmp(&dp->ifp->v6addresses[i],
        !          1300:                                    &dp->link.sin6_addr,
        !          1301:                                    sizeof(dp->link.sin6_addr)))
        !          1302:                                break;
        !          1303:                }
        !          1304:                if (i == dp->ifp->v6address_count)
        !          1305:                        log_fatal("Can't find link address for interface '%s'.",
        !          1306:                                  dp->ifp->name);
        !          1307:                if (!link_is_set)
        !          1308:                        memcpy(&dp->link.sin6_addr,
        !          1309:                               &dp->ifp->v6addresses[i],
        !          1310:                               sizeof(dp->link.sin6_addr));
        !          1311: 
        !          1312:                /* Set interface-id. */
        !          1313:                if (dp->id == -1)
        !          1314:                        dp->id = dp->ifp->index;
        !          1315:        }
        !          1316: 
        !          1317:        for (up = upstreams; up; up = up->next) {
        !          1318:                up->link.sin6_port = local_port;
        !          1319:                up->link.sin6_family = AF_INET6;
        !          1320: #ifdef HAVE_SA_LEN
        !          1321:                up->link.sin6_len = sizeof(up->link);
        !          1322: #endif
        !          1323: 
        !          1324:                if (up->ifp->v6address_count == 0)
        !          1325:                        log_fatal("Interface '%s' has no IPv6 addresses.",
        !          1326:                                  up->ifp->name);
        !          1327:        }
        !          1328: }
        !          1329: 
        !          1330: /*
        !          1331:  * Add DHCPv6 agent options here.
        !          1332:  */
        !          1333: static const int required_forw_opts[] = {
        !          1334:        D6O_INTERFACE_ID,
        !          1335:        D6O_RELAY_MSG,
        !          1336:        0
        !          1337: };
        !          1338: 
        !          1339: /*
        !          1340:  * Process a packet upwards, i.e., from client to server.
        !          1341:  */
        !          1342: static void
        !          1343: process_up6(struct packet *packet, struct stream_list *dp) {
        !          1344:        char forw_data[65535];
        !          1345:        unsigned cursor;
        !          1346:        struct dhcpv6_relay_packet *relay;
        !          1347:        struct option_state *opts;
        !          1348:        struct stream_list *up;
        !          1349: 
        !          1350:        /* Check if the message should be relayed to the server. */
        !          1351:        switch (packet->dhcpv6_msg_type) {
        !          1352:              case DHCPV6_SOLICIT:
        !          1353:              case DHCPV6_REQUEST:
        !          1354:              case DHCPV6_CONFIRM:
        !          1355:              case DHCPV6_RENEW:
        !          1356:              case DHCPV6_REBIND:
        !          1357:              case DHCPV6_RELEASE:
        !          1358:              case DHCPV6_DECLINE:
        !          1359:              case DHCPV6_INFORMATION_REQUEST:
        !          1360:              case DHCPV6_RELAY_FORW:
        !          1361:              case DHCPV6_LEASEQUERY:
        !          1362:                log_info("Relaying %s from %s port %d going up.",
        !          1363:                         dhcpv6_type_names[packet->dhcpv6_msg_type],
        !          1364:                         piaddr(packet->client_addr),
        !          1365:                         ntohs(packet->client_port));
        !          1366:                break;
        !          1367: 
        !          1368:              case DHCPV6_ADVERTISE:
        !          1369:              case DHCPV6_REPLY:
        !          1370:              case DHCPV6_RECONFIGURE:
        !          1371:              case DHCPV6_RELAY_REPL:
        !          1372:              case DHCPV6_LEASEQUERY_REPLY:
        !          1373:                log_info("Discarding %s from %s port %d going up.",
        !          1374:                         dhcpv6_type_names[packet->dhcpv6_msg_type],
        !          1375:                         piaddr(packet->client_addr),
        !          1376:                         ntohs(packet->client_port));
        !          1377:                return;
        !          1378: 
        !          1379:              default:
        !          1380:                log_info("Unknown %d type from %s port %d going up.",
        !          1381:                         packet->dhcpv6_msg_type,
        !          1382:                         piaddr(packet->client_addr),
        !          1383:                         ntohs(packet->client_port));
        !          1384:                return;
        !          1385:        }
        !          1386: 
        !          1387:        /* Build the relay-forward header. */
        !          1388:        relay = (struct dhcpv6_relay_packet *) forw_data;
        !          1389:        cursor = offsetof(struct dhcpv6_relay_packet, options);
        !          1390:        relay->msg_type = DHCPV6_RELAY_FORW;
        !          1391:        if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
        !          1392:                if (packet->dhcpv6_hop_count >= max_hop_count) {
        !          1393:                        log_info("Hop count exceeded,");
        !          1394:                        return;
        !          1395:                }
        !          1396:                relay->hop_count = packet->dhcpv6_hop_count + 1;
        !          1397:                if (dp) {
        !          1398:                        memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
        !          1399:                } else {
        !          1400:                        /* On smart relay add: && !global. */
        !          1401:                        if (!use_if_id && downstreams->next) {
        !          1402:                                log_info("Shan't get back the interface.");
        !          1403:                                return;
        !          1404:                        }
        !          1405:                        memset(&relay->link_address, 0, 16);
        !          1406:                }
        !          1407:        } else {
        !          1408:                relay->hop_count = 0;
        !          1409:                if (!dp)
        !          1410:                        return;
        !          1411:                memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
        !          1412:        }
        !          1413:        memcpy(&relay->peer_address, packet->client_addr.iabuf, 16);
        !          1414: 
        !          1415:        /* Get an option state. */
        !          1416:        opts = NULL;
        !          1417:        if (!option_state_allocate(&opts, MDL)) {
        !          1418:                log_fatal("No memory for upwards options.");
        !          1419:        }
        !          1420:        
        !          1421:        /* Add an interface-id (if used). */
        !          1422:        if (use_if_id) {
        !          1423:                int if_id;
        !          1424: 
        !          1425:                if (dp) {
        !          1426:                        if_id = dp->id;
        !          1427:                } else if (!downstreams->next) {
        !          1428:                        if_id = downstreams->id;
        !          1429:                } else {
        !          1430:                        log_info("Don't know the interface.");
        !          1431:                        option_state_dereference(&opts, MDL);
        !          1432:                        return;
        !          1433:                }
        !          1434: 
        !          1435:                if (!save_option_buffer(&dhcpv6_universe, opts,
        !          1436:                                        NULL, (unsigned char *) &if_id,
        !          1437:                                        sizeof(int),
        !          1438:                                        D6O_INTERFACE_ID, 0)) {
        !          1439:                        log_error("Can't save interface-id.");
        !          1440:                        option_state_dereference(&opts, MDL);
        !          1441:                        return;
        !          1442:                }
        !          1443:        }
        !          1444: 
        !          1445:        /* Add the relay-msg carrying the packet. */
        !          1446:        if (!save_option_buffer(&dhcpv6_universe, opts,
        !          1447:                                NULL, (unsigned char *) packet->raw,
        !          1448:                                packet->packet_length,
        !          1449:                                D6O_RELAY_MSG, 0)) {
        !          1450:                log_error("Can't save relay-msg.");
        !          1451:                option_state_dereference(&opts, MDL);
        !          1452:                return;
        !          1453:        }
        !          1454: 
        !          1455:        /* Finish the relay-forward message. */
        !          1456:        cursor += store_options6(forw_data + cursor,
        !          1457:                                 sizeof(forw_data) - cursor,
        !          1458:                                 opts, packet, 
        !          1459:                                 required_forw_opts, NULL);
        !          1460:        option_state_dereference(&opts, MDL);
        !          1461: 
        !          1462:        /* Send it to all upstreams. */
        !          1463:        for (up = upstreams; up; up = up->next) {
        !          1464:                send_packet6(up->ifp, (unsigned char *) forw_data,
        !          1465:                             (size_t) cursor, &up->link);
        !          1466:        }
        !          1467: }
        !          1468:                             
        !          1469: /*
        !          1470:  * Process a packet downwards, i.e., from server to client.
        !          1471:  */
        !          1472: static void
        !          1473: process_down6(struct packet *packet) {
        !          1474:        struct stream_list *dp;
        !          1475:        struct option_cache *oc;
        !          1476:        struct data_string relay_msg;
        !          1477:        const struct dhcpv6_packet *msg;
        !          1478:        struct data_string if_id;
        !          1479:        struct sockaddr_in6 to;
        !          1480:        struct iaddr peer;
        !          1481: 
        !          1482:        /* The packet must be a relay-reply message. */
        !          1483:        if (packet->dhcpv6_msg_type != DHCPV6_RELAY_REPL) {
        !          1484:                if (packet->dhcpv6_msg_type < dhcpv6_type_name_max)
        !          1485:                        log_info("Discarding %s from %s port %d going down.",
        !          1486:                                 dhcpv6_type_names[packet->dhcpv6_msg_type],
        !          1487:                                 piaddr(packet->client_addr),
        !          1488:                                 ntohs(packet->client_port));
        !          1489:                else
        !          1490:                        log_info("Unknown %d type from %s port %d going down.",
        !          1491:                                 packet->dhcpv6_msg_type,
        !          1492:                                 piaddr(packet->client_addr),
        !          1493:                                 ntohs(packet->client_port));
        !          1494:                return;
        !          1495:        }
        !          1496: 
        !          1497:        /* Inits. */
        !          1498:        memset(&relay_msg, 0, sizeof(relay_msg));
        !          1499:        memset(&if_id, 0, sizeof(if_id));
        !          1500:        memset(&to, 0, sizeof(to));
        !          1501:        to.sin6_family = AF_INET6;
        !          1502: #ifdef HAVE_SA_LEN
        !          1503:        to.sin6_len = sizeof(to);
        !          1504: #endif
        !          1505:        to.sin6_port = remote_port;
        !          1506:        peer.len = 16;
        !          1507: 
        !          1508:        /* Get the relay-msg option (carrying the message to relay). */
        !          1509:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG);
        !          1510:        if (oc == NULL) {
        !          1511:                log_info("No relay-msg.");
        !          1512:                return;
        !          1513:        }
        !          1514:        if (!evaluate_option_cache(&relay_msg, packet, NULL, NULL,
        !          1515:                                   packet->options, NULL,
        !          1516:                                   &global_scope, oc, MDL) ||
        !          1517:            (relay_msg.len < offsetof(struct dhcpv6_packet, options))) {
        !          1518:                log_error("Can't evaluate relay-msg.");
        !          1519:                return;
        !          1520:        }
        !          1521:        msg = (const struct dhcpv6_packet *) relay_msg.data;
        !          1522: 
        !          1523:        /* Get the interface-id (if exists) and the downstream. */
        !          1524:        oc = lookup_option(&dhcpv6_universe, packet->options,
        !          1525:                           D6O_INTERFACE_ID);
        !          1526:        if (oc != NULL) {
        !          1527:                int if_index;
        !          1528: 
        !          1529:                if (!evaluate_option_cache(&if_id, packet, NULL, NULL,
        !          1530:                                           packet->options, NULL,
        !          1531:                                           &global_scope, oc, MDL) ||
        !          1532:                    (if_id.len != sizeof(int))) {
        !          1533:                        log_info("Can't evaluate interface-id.");
        !          1534:                        goto cleanup;
        !          1535:                }
        !          1536:                memcpy(&if_index, if_id.data, sizeof(int));
        !          1537:                for (dp = downstreams; dp; dp = dp->next) {
        !          1538:                        if (dp->id == if_index)
        !          1539:                                break;
        !          1540:                }
        !          1541:        } else {
        !          1542:                if (use_if_id) {
        !          1543:                        /* Require an interface-id. */
        !          1544:                        log_info("No interface-id.");
        !          1545:                        goto cleanup;
        !          1546:                }
        !          1547:                for (dp = downstreams; dp; dp = dp->next) {
        !          1548:                        /* Get the first matching one. */
        !          1549:                        if (!memcmp(&dp->link.sin6_addr,
        !          1550:                                    &packet->dhcpv6_link_address,
        !          1551:                                    sizeof(struct in6_addr)))
        !          1552:                                break;
        !          1553:                }
        !          1554:        }
        !          1555:        /* Why bother when there is no choice. */
        !          1556:        if (!dp && !downstreams->next)
        !          1557:                dp = downstreams;
        !          1558:        if (!dp) {
        !          1559:                log_info("Can't find the down interface.");
        !          1560:                goto cleanup;
        !          1561:        }
        !          1562:        memcpy(peer.iabuf, &packet->dhcpv6_peer_address, peer.len);
        !          1563:        to.sin6_addr = packet->dhcpv6_peer_address;
        !          1564: 
        !          1565:        /* Check if we should relay the carried message. */
        !          1566:        switch (msg->msg_type) {
        !          1567:                /* Relay-Reply of for another relay, not a client. */
        !          1568:              case DHCPV6_RELAY_REPL:
        !          1569:                to.sin6_port = local_port;
        !          1570:                /* Fall into: */
        !          1571: 
        !          1572:              case DHCPV6_ADVERTISE:
        !          1573:              case DHCPV6_REPLY:
        !          1574:              case DHCPV6_RECONFIGURE:
        !          1575:              case DHCPV6_RELAY_FORW:
        !          1576:              case DHCPV6_LEASEQUERY_REPLY:
        !          1577:                log_info("Relaying %s to %s port %d down.",
        !          1578:                         dhcpv6_type_names[msg->msg_type],
        !          1579:                         piaddr(peer),
        !          1580:                         ntohs(to.sin6_port));
        !          1581:                break;
        !          1582: 
        !          1583:              case DHCPV6_SOLICIT:
        !          1584:              case DHCPV6_REQUEST:
        !          1585:              case DHCPV6_CONFIRM:
        !          1586:              case DHCPV6_RENEW:
        !          1587:              case DHCPV6_REBIND:
        !          1588:              case DHCPV6_RELEASE:
        !          1589:              case DHCPV6_DECLINE:
        !          1590:              case DHCPV6_INFORMATION_REQUEST:
        !          1591:              case DHCPV6_LEASEQUERY:
        !          1592:                log_info("Discarding %s to %s port %d down.",
        !          1593:                         dhcpv6_type_names[msg->msg_type],
        !          1594:                         piaddr(peer),
        !          1595:                         ntohs(to.sin6_port));
        !          1596:                goto cleanup;
        !          1597: 
        !          1598:              default:
        !          1599:                log_info("Unknown %d type to %s port %d down.",
        !          1600:                         msg->msg_type,
        !          1601:                         piaddr(peer),
        !          1602:                         ntohs(to.sin6_port));
        !          1603:                goto cleanup;
        !          1604:        }
        !          1605: 
        !          1606:        /* Send the message to the downstream. */
        !          1607:        send_packet6(dp->ifp, (unsigned char *) relay_msg.data,
        !          1608:                     (size_t) relay_msg.len, &to);
        !          1609: 
        !          1610:       cleanup:
        !          1611:        if (relay_msg.data != NULL)
        !          1612:                data_string_forget(&relay_msg, MDL);
        !          1613:        if (if_id.data != NULL)
        !          1614:                data_string_forget(&if_id, MDL);
        !          1615: }
        !          1616: 
        !          1617: /*
        !          1618:  * Called by the dispatch packet handler with a decoded packet.
        !          1619:  */
        !          1620: void
        !          1621: dhcpv6(struct packet *packet) {
        !          1622:        struct stream_list *dp;
        !          1623: 
        !          1624:        /* Try all relay-replies downwards. */
        !          1625:        if (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL) {
        !          1626:                process_down6(packet);
        !          1627:                return;
        !          1628:        }
        !          1629:        /* Others are candidates to go up if they come from down. */
        !          1630:        for (dp = downstreams; dp; dp = dp->next) {
        !          1631:                if (packet->interface != dp->ifp)
        !          1632:                        continue;
        !          1633:                process_up6(packet, dp);
        !          1634:                return;
        !          1635:        }
        !          1636:        /* Relay-forward could work from an unknown interface. */
        !          1637:        if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
        !          1638:                process_up6(packet, NULL);
        !          1639:                return;
        !          1640:        }
        !          1641: 
        !          1642:        log_info("Can't process packet from interface '%s'.",
        !          1643:                 packet->interface->name);
        !          1644: }
        !          1645: #endif
        !          1646: 
        !          1647: /* Stub routines needed for linking with DHCP libraries. */
        !          1648: void
        !          1649: bootp(struct packet *packet) {
        !          1650:        return;
        !          1651: }
        !          1652: 
        !          1653: void
        !          1654: dhcp(struct packet *packet) {
        !          1655:        return;
        !          1656: }
        !          1657: 
        !          1658: void
        !          1659: classify(struct packet *p, struct class *c) {
        !          1660:        return;
        !          1661: }
        !          1662: 
        !          1663: int
        !          1664: check_collection(struct packet *p, struct lease *l, struct collection *c) {
        !          1665:        return 0;
        !          1666: }
        !          1667: 
        !          1668: isc_result_t
        !          1669: find_class(struct class **class, const char *c1, const char *c2, int i) {
        !          1670:        return ISC_R_NOTFOUND;
        !          1671: }
        !          1672: 
        !          1673: int
        !          1674: parse_allow_deny(struct option_cache **oc, struct parse *p, int i) {
        !          1675:        return 0;
        !          1676: }
        !          1677: 
        !          1678: isc_result_t
        !          1679: dhcp_set_control_state(control_object_state_t oldstate,
        !          1680:                       control_object_state_t newstate) {
        !          1681:        return ISC_R_SUCCESS;
        !          1682: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>