Annotation of embedaddon/dhcp/common/upf.c, revision 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, ¶m) < 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>