Annotation of embedaddon/dhcp/common/upf.c, revision 1.1.1.1

1.1       misho       1: /* upf.c
                      2: 
                      3:    Ultrix PacketFilter interface code. */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
                      7:  * Copyright (c) 1996-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: #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
                     37: #include <sys/ioctl.h>
                     38: #include <sys/uio.h>
                     39: 
                     40: #include <net/pfilt.h>
                     41: #include <netinet/in_systm.h>
                     42: #include "includes/netinet/ip.h"
                     43: #include "includes/netinet/udp.h"
                     44: #include "includes/netinet/if_ether.h"
                     45: 
                     46: /* Reinitializes the specified interface after an address change.   This
                     47:    is not required for packet-filter APIs. */
                     48: 
                     49: #ifdef USE_UPF_SEND
                     50: void if_reinitialize_send (info)
                     51:        struct interface_info *info;
                     52: {
                     53: }
                     54: #endif
                     55: 
                     56: #ifdef USE_UPF_RECEIVE
                     57: void if_reinitialize_receive (info)
                     58:        struct interface_info *info;
                     59: {
                     60: }
                     61: #endif
                     62: 
                     63: /* Called by get_interface_list for each interface that's discovered.
                     64:    Opens a packet filter for each interface and adds it to the select
                     65:    mask. */
                     66: 
                     67: int if_register_upf (info)
                     68:        struct interface_info *info;
                     69: {
                     70:        int sock;
                     71:        char filename[50];
                     72:        int b;
                     73:        struct endevp param;
                     74: 
                     75:        /* Open a UPF device */
                     76:        for (b = 0; 1; b++) {
                     77:                /* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */
                     78:                sprintf(filename, "/dev/pf/pfilt%d", b);
                     79: 
                     80:                sock = open (filename, O_RDWR, 0);
                     81:                if (sock < 0) {
                     82:                        if (errno == EBUSY) {
                     83:                                continue;
                     84:                        } else {
                     85:                                log_fatal ("Can't find free upf: %m");
                     86:                        }
                     87:                } else {
                     88:                        break;
                     89:                }
                     90:        }
                     91: 
                     92:        /* Set the UPF device to point at this interface. */
                     93:        if (ioctl (sock, EIOCSETIF, info -> ifp) < 0)
                     94:                log_fatal ("Can't attach interface %s to upf device %s: %m",
                     95:                       info -> name, filename);
                     96: 
                     97:        /* Get the hardware address. */
                     98:        if (ioctl (sock, EIOCDEVP, &param) < 0)
                     99:                log_fatal ("Can't get interface %s hardware address: %m",
                    100:                       info -> name);
                    101: 
                    102:        /* We only know how to do ethernet. */
                    103:        if (param.end_dev_type != ENDT_10MB)    
                    104:                log_fatal ("Invalid device type on network interface %s: %d",
                    105:                       info -> name, param.end_dev_type);
                    106: 
                    107:        if (param.end_addr_len != 6)
                    108:                log_fatal ("Invalid hardware address length on %s: %d",
                    109:                       info -> name, param.end_addr_len);
                    110: 
                    111:        info -> hw_address.hlen = 7;
                    112:        info -> hw_address.hbuf [0] = ARPHRD_ETHER;
                    113:        memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6);
                    114: 
                    115:        return sock;
                    116: }
                    117: #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
                    118: 
                    119: #ifdef USE_UPF_SEND
                    120: void if_register_send (info)
                    121:        struct interface_info *info;
                    122: {
                    123:        /* If we're using the upf API for sending and receiving,
                    124:           we don't need to register this interface twice. */
                    125: #ifndef USE_UPF_RECEIVE
                    126:        info -> wfdesc = if_register_upf (info, interface);
                    127: #else
                    128:        info -> wfdesc = info -> rfdesc;
                    129: #endif
                    130:         if (!quiet_interface_discovery)
                    131:                log_info ("Sending on   UPF/%s/%s%s%s",
                    132:                      info -> name,
                    133:                      print_hw_addr (info -> hw_address.hbuf [0],
                    134:                                     info -> hw_address.hlen - 1,
                    135:                                     &info -> hw_address.hbuf [1]),
                    136:                      (info -> shared_network ? "/" : ""),
                    137:                      (info -> shared_network ?
                    138:                       info -> shared_network -> name : ""));
                    139: }
                    140: 
                    141: void if_deregister_send (info)
                    142:        struct interface_info *info;
                    143: {
                    144: #ifndef USE_UPF_RECEIVE
                    145:        close (info -> wfdesc);
                    146: #endif
                    147:        info -> wfdesc = -1;
                    148:         if (!quiet_interface_discovery)
                    149:                log_info ("Disabling output on UPF/%s/%s%s%s",
                    150:                      info -> name,
                    151:                      print_hw_addr (info -> hw_address.hbuf [0],
                    152:                                     info -> hw_address.hlen - 1,
                    153:                                     &info -> hw_address.hbuf [1]),
                    154:                      (info -> shared_network ? "/" : ""),
                    155:                      (info -> shared_network ?
                    156:                       info -> shared_network -> name : ""));
                    157: }
                    158: #endif /* USE_UPF_SEND */
                    159: 
                    160: #ifdef USE_UPF_RECEIVE
                    161: /* Packet filter program...
                    162:    XXX Changes to the filter program may require changes to the constant
                    163:    offsets used in if_register_send to patch the UPF program! XXX */
                    164: 
                    165: 
                    166: void if_register_receive (info)
                    167:        struct interface_info *info;
                    168: {
                    169:        int flag = 1;
                    170:        u_int32_t addr;
                    171:        struct enfilter pf;
                    172:        u_int32_t bits;
                    173: 
                    174:        /* Open a UPF device and hang it on this interface... */
                    175:        info -> rfdesc = if_register_upf (info);
                    176: 
                    177:        /* Allow the copyall flag to be set... */
                    178:        if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
                    179:                log_fatal ("Can't set ALLOWCOPYALL: %m");
                    180: 
                    181:        /* Clear all the packet filter mode bits first... */
                    182:        flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
                    183:                ENNONEXCL | ENCOPYALL);
                    184:        if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
                    185:                log_fatal ("Can't clear pfilt bits: %m");
                    186: 
                    187:        /* Set the ENBATCH and ENCOPYALL bits... */
                    188:        bits = ENBATCH | ENCOPYALL;
                    189:        if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
                    190:                log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
                    191: 
                    192:        /* Set up the UPF filter program. */
                    193:        /* XXX Unlike the BPF filter program, this one won't work if the
                    194:           XXX IP packet is fragmented or if there are options on the IP
                    195:           XXX header. */
                    196:        pf.enf_Priority = 0;
                    197:        pf.enf_FilterLen = 0;
                    198: 
                    199:        pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
                    200:        pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
                    201:        pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
                    202:        pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
                    203:        pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
                    204:        pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
                    205:        pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
                    206:        pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
                    207:        pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
                    208:        pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
                    209:        pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
                    210:        pf.enf_Filter [pf.enf_FilterLen++] = local_port;
                    211: 
                    212:        if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
                    213:                log_fatal ("Can't install packet filter program: %m");
                    214:         if (!quiet_interface_discovery)
                    215:                log_info ("Listening on UPF/%s/%s%s%s",
                    216:                      info -> name,
                    217:                      print_hw_addr (info -> hw_address.hbuf [0],
                    218:                                     info -> hw_address.hlen - 1,
                    219:                                     &info -> hw_address.hbuf [1]),
                    220:                      (info -> shared_network ? "/" : ""),
                    221:                      (info -> shared_network ?
                    222:                       info -> shared_network -> name : ""));
                    223: }
                    224: 
                    225: void if_deregister_receive (info)
                    226:        struct interface_info *info;
                    227: {
                    228:        close (info -> rfdesc);
                    229:        info -> rfdesc = -1;
                    230:         if (!quiet_interface_discovery)
                    231:                log_info ("Disabling input on UPF/%s/%s%s%s",
                    232:                      info -> name,
                    233:                      print_hw_addr (info -> hw_address.hbuf [0],
                    234:                                     info -> hw_address.hlen - 1,
                    235:                                     &info -> hw_address.hbuf [1]),
                    236:                      (info -> shared_network ? "/" : ""),
                    237:                      (info -> shared_network ?
                    238:                       info -> shared_network -> name : ""));
                    239: }
                    240: #endif /* USE_UPF_RECEIVE */
                    241: 
                    242: #ifdef USE_UPF_SEND
                    243: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
                    244:        struct interface_info *interface;
                    245:        struct packet *packet;
                    246:        struct dhcp_packet *raw;
                    247:        size_t len;
                    248:        struct in_addr from;
                    249:        struct sockaddr_in *to;
                    250:        struct hardware *hto;
                    251: {
                    252:        unsigned hbufp = 0, ibufp = 0;
                    253:        double hw [4];
                    254:        double ip [32];
                    255:        struct iovec iov [3];
                    256:        int result;
                    257:        int fudge;
                    258: 
                    259:        if (!strcmp (interface -> name, "fallback"))
                    260:                return send_fallback (interface, packet, raw,
                    261:                                      len, from, to, hto);
                    262: 
                    263:        /* Assemble the headers... */
                    264:        assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
                    265:        assemble_udp_ip_header (interface,
                    266:                                (unsigned char *)ip, &ibufp, from.s_addr,
                    267:                                to -> sin_addr.s_addr, to -> sin_port,
                    268:                                (unsigned char *)raw, len);
                    269: 
                    270:        /* Fire it off */
                    271:        iov [0].iov_base = ((char *)hw);
                    272:        iov [0].iov_len = hbufp;
                    273:        iov [1].iov_base = ((char *)ip);
                    274:        iov [1].iov_len = ibufp;
                    275:        iov [2].iov_base = (char *)raw;
                    276:        iov [2].iov_len = len;
                    277: 
                    278:        result = writev(interface -> wfdesc, iov, 3);
                    279:        if (result < 0)
                    280:                log_error ("send_packet: %m");
                    281:        return result;
                    282: }
                    283: #endif /* USE_UPF_SEND */
                    284: 
                    285: #ifdef USE_UPF_RECEIVE
                    286: ssize_t receive_packet (interface, buf, len, from, hfrom)
                    287:        struct interface_info *interface;
                    288:        unsigned char *buf;
                    289:        size_t len;
                    290:        struct sockaddr_in *from;
                    291:        struct hardware *hfrom;
                    292: {
                    293:        int nread;
                    294:        int length = 0;
                    295:        int offset = 0;
                    296:        unsigned char ibuf [1500 + sizeof (struct enstamp)];
                    297:        int bufix = 0;
                    298:        unsigned paylen;
                    299: 
                    300:        length = read (interface -> rfdesc, ibuf, sizeof ibuf);
                    301:        if (length <= 0)
                    302:                return length;
                    303: 
                    304:        bufix = sizeof (struct enstamp);
                    305:        /* Decode the physical header... */
                    306:        offset = decode_hw_header (interface, ibuf, bufix, hfrom);
                    307: 
                    308:        /* If a physical layer checksum failed (dunno of any
                    309:           physical layer that supports this, but WTH), skip this
                    310:           packet. */
                    311:        if (offset < 0) {
                    312:                return 0;
                    313:        }
                    314: 
                    315:        bufix += offset;
                    316:        length -= offset;
                    317: 
                    318:        /* Decode the IP and UDP headers... */
                    319:        offset = decode_udp_ip_header (interface, ibuf, bufix,
                    320:                                       from, length, &paylen);
                    321: 
                    322:        /* If the IP or UDP checksum was bad, skip the packet... */
                    323:        if (offset < 0)
                    324:                return 0;
                    325: 
                    326:        bufix += offset;
                    327:        length -= offset;
                    328: 
                    329:        if (length < paylen)
                    330:                log_fatal("Internal inconsistency at %s:%d.", MDL);
                    331: 
                    332:        /* Copy out the data in the packet... */
                    333:        memcpy (buf, &ibuf[bufix], paylen);
                    334:        return paylen;
                    335: }
                    336: 
                    337: int can_unicast_without_arp (ip)
                    338:        struct interface_info *ip;
                    339: {
                    340:        return 1;
                    341: }
                    342: 
                    343: int can_receive_unicast_unconfigured (ip)
                    344:        struct interface_info *ip;
                    345: {
                    346:        return 1;
                    347: }
                    348: 
                    349: int supports_multiple_interfaces (ip)
                    350:        struct interface_info *ip;
                    351: {
                    352:        return 1;
                    353: }
                    354: 
                    355: void maybe_setup_fallback ()
                    356: {
                    357:        isc_result_t status;
                    358:        struct interface_info *fbi = (struct interface_info *)0;
                    359:        if (setup_fallback (&fbi, MDL)) {
                    360:                if_register_fallback (fbi);
                    361:                status = omapi_register_io_object ((omapi_object_t *)fbi,
                    362:                                                   if_readsocket, 0,
                    363:                                                   fallback_discard, 0, 0);
                    364:                if (status != ISC_R_SUCCESS)
                    365:                        log_fatal ("Can't register I/O handle for %s: %s",
                    366:                                   fbi -> name, isc_result_totext (status));
                    367:                interface_dereference (&fbi, MDL);
                    368:        }
                    369: }
                    370: #endif

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