Annotation of embedaddon/dhcp/common/dlpi.c, revision 1.1
1.1 ! misho 1: /* dlpi.c
! 2:
! 3: Data Link Provider Interface (DLPI) network interface code. */
! 4:
! 5: /*
! 6: * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC")
! 7: * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
! 8: * Copyright (c) 1996-2003 by Internet Software Consortium
! 9: *
! 10: * Permission to use, copy, modify, and distribute this software for any
! 11: * purpose with or without fee is hereby granted, provided that the above
! 12: * copyright notice and this permission notice appear in all copies.
! 13: *
! 14: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
! 15: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 16: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
! 17: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 18: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 19: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
! 20: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 21: *
! 22: * Internet Systems Consortium, Inc.
! 23: * 950 Charter Street
! 24: * Redwood City, CA 94063
! 25: * <info@isc.org>
! 26: * https://www.isc.org/
! 27: *
! 28: * This software was written for Internet Systems Consortium
! 29: * by Eric James Negaard, <lmdejn@lmd.ericsson.se>. To learn more about
! 30: * Internet Systems Consortium, see ``https://www.isc.org''.
! 31: *
! 32: * Joost Mulders has also done considerable work in debugging the DLPI API
! 33: * support on Solaris and getting this code to work properly on a variety
! 34: * of different Solaris platforms.
! 35: */
! 36:
! 37: /*
! 38: * Based largely in part to the existing NIT code in nit.c.
! 39: *
! 40: * This code has been developed and tested on sparc-based machines running
! 41: * SunOS 5.5.1, with le and hme network interfaces. It should be pretty
! 42: * generic, though.
! 43: */
! 44:
! 45: /*
! 46: * Implementation notes:
! 47: *
! 48: * I first tried to write this code to the "vanilla" DLPI 2.0 API.
! 49: * It worked on a Sun Ultra-1 with a hme interface, but didn't work
! 50: * on Sun SparcStation 5's with "le" interfaces (the packets sent out
! 51: * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead
! 52: * of the expected 0x0800).
! 53: *
! 54: * Therefore I added the "DLPI_RAW" code which is a Sun extension to
! 55: * the DLPI standard. This code works on both of the above machines.
! 56: * This is configurable in the OS-dependent include file by defining
! 57: * USE_DLPI_RAW.
! 58: *
! 59: * It quickly became apparant that I should also use the "pfmod"
! 60: * STREAMS module to cut down on the amount of user level packet
! 61: * processing. I don't know how widely available "pfmod" is, so it's
! 62: * use is conditionally included. This is configurable in the
! 63: * OS-dependent include file by defining USE_DLPI_PFMOD.
! 64: *
! 65: * A major quirk on the Sun's at least, is that no packets seem to get
! 66: * sent out the interface until six seconds after the interface is
! 67: * first "attached" to [per system reboot] (it's actually from when
! 68: * the interface is attached, not when it is plumbed, so putting a
! 69: * sleep into the dhclient-script at PREINIT time doesn't help). I
! 70: * HAVE tried, without success to poll the fd to see when it is ready
! 71: * for writing. This doesn't help at all. If the sleeps are not done,
! 72: * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so
! 73: * I've put them here, when register_send and register_receive are
! 74: * called (split up into two three-second sleeps between the notices,
! 75: * so that it doesn't seem like so long when you're watching :-). The
! 76: * amount of time to sleep is configurable in the OS-dependent include
! 77: * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds
! 78: * to sleep.
! 79: */
! 80:
! 81: /*
! 82: * The Open Group Technical Standard can be found here:
! 83: * http://www.opengroup.org/onlinepubs/009618899/index.htm
! 84: *
! 85: * The HP DLPI Programmer's Guide can be found here:
! 86: * http://docs.hp.com/en/B2355-90139/index.html
! 87: */
! 88:
! 89: #include "dhcpd.h"
! 90:
! 91: #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) || \
! 92: defined(USE_DLPI_HWADDR)
! 93:
! 94: # include <sys/ioctl.h>
! 95: # include <sys/time.h>
! 96: # include <sys/dlpi.h>
! 97: # include <stropts.h>
! 98: # ifdef USE_DLPI_PFMOD
! 99: # include <sys/pfmod.h>
! 100: # endif
! 101: #include <poll.h>
! 102: #include <errno.h>
! 103:
! 104: # include <netinet/in_systm.h>
! 105: # include "includes/netinet/ip.h"
! 106: # include "includes/netinet/udp.h"
! 107: # include "includes/netinet/if_ether.h"
! 108:
! 109: # ifdef USE_DLPI_PFMOD
! 110: # ifdef USE_DLPI_RAW
! 111: # define DLPI_MODNAME "DLPI+RAW+PFMOD"
! 112: # else
! 113: # define DLPI_MODNAME "DLPI+PFMOD"
! 114: # endif
! 115: # else
! 116: # ifdef USE_DLPI_RAW
! 117: # define DLPI_MODNAME "DLPI+RAW"
! 118: # else
! 119: # define DLPI_MODNAME "DLPI"
! 120: # endif
! 121: # endif
! 122:
! 123: # ifndef ABS
! 124: # define ABS(x) ((x) >= 0 ? (x) : 0-(x))
! 125: # endif
! 126:
! 127: #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
! 128: static int strioctl (int fd, int cmd, int timeout, int len, char *dp);
! 129: #endif
! 130:
! 131: #define DLPI_MAXDLBUF 8192 /* Buffer size */
! 132: #define DLPI_MAXDLADDR 1024 /* Max address size */
! 133: #define DLPI_DEVDIR "/dev/" /* Device directory */
! 134:
! 135: static int dlpiopen(const char *ifname);
! 136: static int dlpiunit (char *ifname);
! 137: static int dlpiinforeq (int fd);
! 138: static int dlpiphysaddrreq (int fd, unsigned long addrtype);
! 139: static int dlpiattachreq (int fd, unsigned long ppa);
! 140: static int dlpibindreq (int fd, unsigned long sap, unsigned long max_conind,
! 141: unsigned long service_mode, unsigned long conn_mgmt,
! 142: unsigned long xidtest);
! 143: #if defined(UNUSED_DLPI_INTERFACE)
! 144: /* These functions are unused at present, but may be used at a later date.
! 145: * defined out to avoid compiler warnings about unused static functions.
! 146: */
! 147: static int dlpidetachreq (int fd);
! 148: static int dlpiunbindreq (int fd);
! 149: #endif
! 150: static int dlpiokack (int fd, char *bufp);
! 151: static int dlpiinfoack (int fd, char *bufp);
! 152: static int dlpiphysaddrack (int fd, char *bufp);
! 153: static int dlpibindack (int fd, char *bufp);
! 154: #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE)
! 155: /* These functions are not used if we're only sourcing the get_hw_addr()
! 156: * function (for USE_SOCKETS).
! 157: */
! 158: static int dlpiunitdatareq (int fd, unsigned char *addr, int addrlen,
! 159: unsigned long minpri, unsigned long maxpri,
! 160: unsigned char *data, int datalen);
! 161: static int dlpiunitdataind (int fd,
! 162: unsigned char *dstaddr,
! 163: unsigned long *dstaddrlen,
! 164: unsigned char *srcaddr,
! 165: unsigned long *srcaddrlen,
! 166: unsigned long *grpaddr,
! 167: unsigned char *data,
! 168: int datalen);
! 169: #endif /* !USE_DLPI_HWADDR: USE_DLPI_SEND || USE_DLPI_RECEIVE */
! 170: static int expected (unsigned long prim, union DL_primitives *dlp,
! 171: int msgflags);
! 172: static int strgetmsg (int fd, struct strbuf *ctlp, struct strbuf *datap,
! 173: int *flagsp, char *caller);
! 174:
! 175: /* Reinitializes the specified interface after an address change. This
! 176: is not required for packet-filter APIs. */
! 177:
! 178: #ifdef USE_DLPI_SEND
! 179: void if_reinitialize_send (info)
! 180: struct interface_info *info;
! 181: {
! 182: }
! 183: #endif
! 184:
! 185: #ifdef USE_DLPI_RECEIVE
! 186: void if_reinitialize_receive (info)
! 187: struct interface_info *info;
! 188: {
! 189: }
! 190: #endif
! 191:
! 192: /* Called by get_interface_list for each interface that's discovered.
! 193: Opens a packet filter for each interface and adds it to the select
! 194: mask. */
! 195:
! 196: int if_register_dlpi (info)
! 197: struct interface_info *info;
! 198: {
! 199: int sock;
! 200: int unit;
! 201: long buf [DLPI_MAXDLBUF];
! 202: union DL_primitives *dlp;
! 203:
! 204: dlp = (union DL_primitives *)buf;
! 205:
! 206: /* Open a DLPI device */
! 207: if ((sock = dlpiopen (info -> name)) < 0) {
! 208: log_fatal ("Can't open DLPI device for %s: %m", info -> name);
! 209: }
! 210:
! 211: /*
! 212: * Submit a DL_INFO_REQ request, to find the dl_mac_type and
! 213: * dl_provider_style
! 214: */
! 215: if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
! 216: log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
! 217: } else {
! 218: switch (dlp -> info_ack.dl_mac_type) {
! 219: case DL_CSMACD: /* IEEE 802.3 */
! 220: case DL_ETHER:
! 221: info -> hw_address.hbuf [0] = HTYPE_ETHER;
! 222: break;
! 223: /* adding token ring 5/1999 - mayer@ping.at */
! 224: case DL_TPR:
! 225: info -> hw_address.hbuf [0] = HTYPE_IEEE802;
! 226: break;
! 227: case DL_FDDI:
! 228: info -> hw_address.hbuf [0] = HTYPE_FDDI;
! 229: break;
! 230: default:
! 231: log_fatal("%s: unsupported DLPI MAC type %lu", info->name,
! 232: (unsigned long)dlp->info_ack.dl_mac_type);
! 233: break;
! 234: }
! 235: /*
! 236: * copy the sap length and broadcast address of this interface
! 237: * to interface_info. This fixes nothing but seemed nicer than to
! 238: * assume -2 and ffffff.
! 239: */
! 240: info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length;
! 241: info -> dlpi_broadcast_addr.hlen =
! 242: dlp -> info_ack.dl_brdcst_addr_length;
! 243: memcpy (info -> dlpi_broadcast_addr.hbuf,
! 244: (char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset,
! 245: dlp -> info_ack.dl_brdcst_addr_length);
! 246: }
! 247:
! 248: if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
! 249: /*
! 250: * Attach to the device. If this fails, the device
! 251: * does not exist.
! 252: */
! 253: unit = dlpiunit (info -> name);
! 254:
! 255: if (dlpiattachreq (sock, unit) < 0
! 256: || dlpiokack (sock, (char *)buf) < 0) {
! 257: log_fatal ("Can't attach DLPI device for %s: %m", info -> name);
! 258: }
! 259: }
! 260:
! 261: /*
! 262: * Bind to the IP service access point (SAP), connectionless (CLDLS).
! 263: */
! 264: if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0
! 265: || dlpibindack (sock, (char *)buf) < 0) {
! 266: log_fatal ("Can't bind DLPI device for %s: %m", info -> name);
! 267: }
! 268:
! 269: /*
! 270: * Submit a DL_PHYS_ADDR_REQ request, to find
! 271: * the hardware address
! 272: */
! 273: if (dlpiphysaddrreq (sock, DL_CURR_PHYS_ADDR) < 0
! 274: || dlpiphysaddrack (sock, (char *)buf) < 0) {
! 275: log_fatal ("Can't get DLPI hardware address for %s: %m",
! 276: info -> name);
! 277: }
! 278:
! 279: info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1;
! 280: memcpy (&info -> hw_address.hbuf [1],
! 281: (char *)buf + dlp -> physaddr_ack.dl_addr_offset,
! 282: dlp -> physaddr_ack.dl_addr_length);
! 283:
! 284: #ifdef USE_DLPI_RAW
! 285: if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) {
! 286: log_fatal ("Can't set DLPI RAW mode for %s: %m",
! 287: info -> name);
! 288: }
! 289: #endif
! 290:
! 291: #ifdef USE_DLPI_PFMOD
! 292: if (ioctl (sock, I_PUSH, "pfmod") < 0) {
! 293: log_fatal ("Can't push packet filter onto DLPI for %s: %m",
! 294: info -> name);
! 295: }
! 296: #endif
! 297:
! 298: return sock;
! 299: }
! 300:
! 301: #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
! 302: static int
! 303: strioctl (fd, cmd, timeout, len, dp)
! 304: int fd;
! 305: int cmd;
! 306: int timeout;
! 307: int len;
! 308: char *dp;
! 309: {
! 310: struct strioctl sio;
! 311: int rslt;
! 312:
! 313: sio.ic_cmd = cmd;
! 314: sio.ic_timout = timeout;
! 315: sio.ic_len = len;
! 316: sio.ic_dp = dp;
! 317:
! 318: if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
! 319: return rslt;
! 320: } else {
! 321: return sio.ic_len;
! 322: }
! 323: }
! 324: #endif /* USE_DPI_PFMOD || USE_DLPI_RAW */
! 325:
! 326: #ifdef USE_DLPI_SEND
! 327: void if_register_send (info)
! 328: struct interface_info *info;
! 329: {
! 330: /* If we're using the DLPI API for sending and receiving,
! 331: we don't need to register this interface twice. */
! 332: #ifndef USE_DLPI_RECEIVE
! 333: # ifdef USE_DLPI_PFMOD
! 334: struct packetfilt pf;
! 335: # endif
! 336:
! 337: info -> wfdesc = if_register_dlpi (info);
! 338:
! 339: # ifdef USE_DLPI_PFMOD
! 340: /* Set up an PFMOD filter that rejects everything... */
! 341: pf.Pf_Priority = 0;
! 342: pf.Pf_FilterLen = 1;
! 343: pf.Pf_Filter [0] = ENF_PUSHZERO;
! 344:
! 345: /* Install the filter */
! 346: if (strioctl (info -> wfdesc, PFIOCSETF, INFTIM,
! 347: sizeof (pf), (char *)&pf) < 0) {
! 348: log_fatal ("Can't set PFMOD send filter on %s: %m", info -> name);
! 349: }
! 350:
! 351: # endif /* USE_DLPI_PFMOD */
! 352: #else /* !defined (USE_DLPI_RECEIVE) */
! 353: /*
! 354: * If using DLPI for both send and receive, simply re-use
! 355: * the read file descriptor that was set up earlier.
! 356: */
! 357: info -> wfdesc = info -> rfdesc;
! 358: #endif
! 359:
! 360: if (!quiet_interface_discovery)
! 361: log_info ("Sending on DLPI/%s/%s%s%s",
! 362: info -> name,
! 363: print_hw_addr (info -> hw_address.hbuf [0],
! 364: info -> hw_address.hlen - 1,
! 365: &info -> hw_address.hbuf [1]),
! 366: (info -> shared_network ? "/" : ""),
! 367: (info -> shared_network ?
! 368: info -> shared_network -> name : ""));
! 369:
! 370: #ifdef DLPI_FIRST_SEND_WAIT
! 371: /* See the implementation notes at the beginning of this file */
! 372: # ifdef USE_DLPI_RECEIVE
! 373: sleep (DLPI_FIRST_SEND_WAIT - (DLPI_FIRST_SEND_WAIT / 2));
! 374: # else
! 375: sleep (DLPI_FIRST_SEND_WAIT);
! 376: # endif
! 377: #endif
! 378: }
! 379:
! 380: void if_deregister_send (info)
! 381: struct interface_info *info;
! 382: {
! 383: /* If we're using the DLPI API for sending and receiving,
! 384: we don't need to register this interface twice. */
! 385: #ifndef USE_DLPI_RECEIVE
! 386: close (info -> wfdesc);
! 387: #endif
! 388: info -> wfdesc = -1;
! 389:
! 390: if (!quiet_interface_discovery)
! 391: log_info ("Disabling output on DLPI/%s/%s%s%s",
! 392: info -> name,
! 393: print_hw_addr (info -> hw_address.hbuf [0],
! 394: info -> hw_address.hlen - 1,
! 395: &info -> hw_address.hbuf [1]),
! 396: (info -> shared_network ? "/" : ""),
! 397: (info -> shared_network ?
! 398: info -> shared_network -> name : ""));
! 399: }
! 400: #endif /* USE_DLPI_SEND */
! 401:
! 402: #ifdef USE_DLPI_RECEIVE
! 403: /* Packet filter program...
! 404: XXX Changes to the filter program may require changes to the constant
! 405: offsets used in if_register_send to patch the NIT program! XXX */
! 406:
! 407: void if_register_receive (info)
! 408: struct interface_info *info;
! 409: {
! 410: #ifdef USE_DLPI_PFMOD
! 411: struct packetfilt pf;
! 412: struct ip iphdr;
! 413: u_int16_t offset;
! 414: #endif
! 415:
! 416: /* Open a DLPI device and hang it on this interface... */
! 417: info -> rfdesc = if_register_dlpi (info);
! 418:
! 419: #ifdef USE_DLPI_PFMOD
! 420: /* Set up the PFMOD filter program. */
! 421: /* XXX Unlike the BPF filter program, this one won't work if the
! 422: XXX IP packet is fragmented or if there are options on the IP
! 423: XXX header. */
! 424: pf.Pf_Priority = 0;
! 425: pf.Pf_FilterLen = 0;
! 426:
! 427: #if defined (USE_DLPI_RAW)
! 428: # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
! 429: /*
! 430: * ethertype == ETHERTYPE_IP
! 431: */
! 432: offset = 12;
! 433: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
! 434: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
! 435: pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
! 436: # else
! 437: # define ETHER_H_PREFIX (0)
! 438: # endif /* USE_DLPI_RAW */
! 439: /*
! 440: * The packets that will be received on this file descriptor
! 441: * will be IP packets (due to the SAP that was specified in
! 442: * the dlbind call). There will be no ethernet header.
! 443: * Therefore, setup the packet filter to check the protocol
! 444: * field for UDP, and the destination port number equal
! 445: * to the local port. All offsets are relative to the start
! 446: * of an IP packet.
! 447: */
! 448:
! 449: /*
! 450: * BOOTPS destination port
! 451: */
! 452: offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t);
! 453: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
! 454: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
! 455: pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
! 456:
! 457: /*
! 458: * protocol should be udp. this is a byte compare, test for
! 459: * endianess.
! 460: */
! 461: offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *)&iphdr);
! 462: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
! 463: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND;
! 464: pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF);
! 465: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
! 466: pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
! 467:
! 468: /* Install the filter... */
! 469: if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM,
! 470: sizeof (pf), (char *)&pf) < 0) {
! 471: log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name);
! 472: }
! 473: #endif /* USE_DLPI_PFMOD */
! 474:
! 475: if (!quiet_interface_discovery)
! 476: log_info ("Listening on DLPI/%s/%s%s%s",
! 477: info -> name,
! 478: print_hw_addr (info -> hw_address.hbuf [0],
! 479: info -> hw_address.hlen - 1,
! 480: &info -> hw_address.hbuf [1]),
! 481: (info -> shared_network ? "/" : ""),
! 482: (info -> shared_network ?
! 483: info -> shared_network -> name : ""));
! 484:
! 485: #ifdef DLPI_FIRST_SEND_WAIT
! 486: /* See the implementation notes at the beginning of this file */
! 487: # ifdef USE_DLPI_SEND
! 488: sleep (DLPI_FIRST_SEND_WAIT / 2);
! 489: # else
! 490: sleep (DLPI_FIRST_SEND_WAIT);
! 491: # endif
! 492: #endif
! 493: }
! 494:
! 495: void if_deregister_receive (info)
! 496: struct interface_info *info;
! 497: {
! 498: /* If we're using the DLPI API for sending and receiving,
! 499: we don't need to register this interface twice. */
! 500: #ifndef USE_DLPI_SEND
! 501: close (info -> rfdesc);
! 502: #endif
! 503: info -> rfdesc = -1;
! 504:
! 505: if (!quiet_interface_discovery)
! 506: log_info ("Disabling input on DLPI/%s/%s%s%s",
! 507: info -> name,
! 508: print_hw_addr (info -> hw_address.hbuf [0],
! 509: info -> hw_address.hlen - 1,
! 510: &info -> hw_address.hbuf [1]),
! 511: (info -> shared_network ? "/" : ""),
! 512: (info -> shared_network ?
! 513: info -> shared_network -> name : ""));
! 514: }
! 515: #endif /* USE_DLPI_RECEIVE */
! 516:
! 517: #ifdef USE_DLPI_SEND
! 518: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
! 519: struct interface_info *interface;
! 520: struct packet *packet;
! 521: struct dhcp_packet *raw;
! 522: size_t len;
! 523: struct in_addr from;
! 524: struct sockaddr_in *to;
! 525: struct hardware *hto;
! 526: {
! 527: #ifdef USE_DLPI_RAW
! 528: double hh [32];
! 529: #endif
! 530: double ih [1536 / sizeof (double)];
! 531: unsigned char *dbuf = (unsigned char *)ih;
! 532: unsigned dbuflen;
! 533: unsigned char dstaddr [DLPI_MAXDLADDR];
! 534: unsigned addrlen;
! 535: int result;
! 536: int fudge;
! 537:
! 538: if (!strcmp (interface -> name, "fallback"))
! 539: return send_fallback (interface, packet, raw,
! 540: len, from, to, hto);
! 541:
! 542: dbuflen = 0;
! 543:
! 544: /* Assemble the headers... */
! 545: #ifdef USE_DLPI_RAW
! 546: assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto);
! 547: if (dbuflen > sizeof hh)
! 548: log_fatal ("send_packet: hh buffer too small.\n");
! 549: fudge = dbuflen % 4; /* IP header must be word-aligned. */
! 550: memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen);
! 551: dbuflen += fudge;
! 552: #else
! 553: fudge = 0;
! 554: #endif
! 555: assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr,
! 556: to -> sin_addr.s_addr, to -> sin_port,
! 557: (unsigned char *)raw, len);
! 558:
! 559: /* Copy the data into the buffer (yuk). */
! 560: memcpy (dbuf + dbuflen, raw, len);
! 561: dbuflen += len;
! 562:
! 563: #ifdef USE_DLPI_RAW
! 564: result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
! 565: #else
! 566:
! 567: /*
! 568: * Setup the destination address (DLSAP) in dstaddr
! 569: *
! 570: * If sap_length < 0 we must deliver the DLSAP as phys+sap.
! 571: * If sap_length > 0 we must deliver the DLSAP as sap+phys.
! 572: *
! 573: * sap = Service Access Point == ETHERTYPE_IP
! 574: * sap + datalink address is called DLSAP in dlpi speak.
! 575: */
! 576: { /* ENCODE DLSAP */
! 577: unsigned char phys [DLPI_MAXDLADDR];
! 578: unsigned char sap [4];
! 579: int sap_len = interface -> dlpi_sap_length;
! 580: int phys_len = interface -> hw_address.hlen - 1;
! 581:
! 582: /* sap = htons (ETHERTYPE_IP) kludge */
! 583: memset (sap, 0, sizeof (sap));
! 584: # if (BYTE_ORDER == LITTLE_ENDIAN)
! 585: sap [0] = 0x00;
! 586: sap [1] = 0x08;
! 587: # else
! 588: sap [0] = 0x08;
! 589: sap [1] = 0x00;
! 590: # endif
! 591:
! 592: if (hto && hto -> hlen == interface -> hw_address.hlen)
! 593: memcpy ( phys, (char *) &hto -> hbuf [1], phys_len);
! 594: else
! 595: memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf,
! 596: interface -> dlpi_broadcast_addr.hlen);
! 597:
! 598: if (sap_len < 0) {
! 599: memcpy ( dstaddr, phys, phys_len);
! 600: memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len));
! 601: }
! 602: else {
! 603: memcpy ( dstaddr, (void *) sap, sap_len);
! 604: memcpy ( (char *) &dstaddr [sap_len], phys, phys_len);
! 605: }
! 606: addrlen = phys_len + ABS (sap_len);
! 607: } /* ENCODE DLSAP */
! 608:
! 609: result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
! 610: 0, 0, dbuf, dbuflen);
! 611: #endif /* USE_DLPI_RAW */
! 612: if (result < 0)
! 613: log_error ("send_packet: %m");
! 614: return result;
! 615: }
! 616: #endif /* USE_DLPI_SEND */
! 617:
! 618: #ifdef USE_DLPI_RECEIVE
! 619: ssize_t receive_packet (interface, buf, len, from, hfrom)
! 620: struct interface_info *interface;
! 621: unsigned char *buf;
! 622: size_t len;
! 623: struct sockaddr_in *from;
! 624: struct hardware *hfrom;
! 625: {
! 626: unsigned char dbuf [1536];
! 627: unsigned char srcaddr [DLPI_MAXDLADDR];
! 628: unsigned long srcaddrlen;
! 629: int length = 0;
! 630: int offset = 0;
! 631: int bufix = 0;
! 632: unsigned paylen;
! 633:
! 634: #ifdef USE_DLPI_RAW
! 635: length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
! 636: #else
! 637: length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL,
! 638: (unsigned long *)NULL, srcaddr, &srcaddrlen,
! 639: (unsigned long *)NULL, dbuf, sizeof (dbuf));
! 640: #endif
! 641:
! 642: if (length <= 0) {
! 643: log_error("receive_packet: %m");
! 644: return length;
! 645: }
! 646:
! 647: # if !defined (USE_DLPI_RAW)
! 648: /*
! 649: * Copy the sender's hw address into hfrom
! 650: * If sap_len < 0 the DLSAP is as phys+sap.
! 651: * If sap_len > 0 the DLSAP is as sap+phys.
! 652: *
! 653: * sap is discarded here.
! 654: */
! 655: { /* DECODE DLSAP */
! 656: int sap_len = interface -> dlpi_sap_length;
! 657: int phys_len = interface -> hw_address.hlen - 1;
! 658:
! 659: if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) {
! 660: hfrom -> hbuf [0] = interface -> hw_address.hbuf [0];
! 661: hfrom -> hlen = interface -> hw_address.hlen;
! 662:
! 663: if (sap_len < 0) {
! 664: memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len);
! 665: }
! 666: else {
! 667: memcpy((char *)&hfrom->hbuf[1], srcaddr + sap_len, phys_len);
! 668: }
! 669: }
! 670: else if (hfrom) {
! 671: memset (hfrom, '\0', sizeof *hfrom);
! 672: }
! 673: } /* DECODE_DLSAP */
! 674:
! 675: # endif /* !defined (USE_DLPI_RAW) */
! 676:
! 677: /* Decode the IP and UDP headers... */
! 678: bufix = 0;
! 679: #ifdef USE_DLPI_RAW
! 680: /* Decode the physical header... */
! 681: offset = decode_hw_header (interface, dbuf, bufix, hfrom);
! 682:
! 683: /* If a physical layer checksum failed (dunno of any
! 684: physical layer that supports this, but WTH), skip this
! 685: packet. */
! 686: if (offset < 0) {
! 687: return 0;
! 688: }
! 689: bufix += offset;
! 690: length -= offset;
! 691: #endif
! 692: offset = decode_udp_ip_header (interface, dbuf, bufix,
! 693: from, length, &paylen);
! 694:
! 695: /*
! 696: * If the IP or UDP checksum was bad, skip the packet...
! 697: *
! 698: * Note: this happens all the time when writing packets via the
! 699: * fallback socket. The packet received by streams does not have
! 700: * the IP or UDP checksums filled in, as those are calculated by
! 701: * the hardware.
! 702: */
! 703: if (offset < 0) {
! 704: return 0;
! 705: }
! 706:
! 707: bufix += offset;
! 708: length -= offset;
! 709:
! 710: if (length < paylen)
! 711: log_fatal("Internal inconsistency at %s:%d.", MDL);
! 712:
! 713: /* Copy out the data in the packet... */
! 714: memcpy(buf, &dbuf [bufix], paylen);
! 715: return paylen;
! 716: }
! 717: #endif
! 718:
! 719: /* Common DLPI routines ...
! 720: *
! 721: * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
! 722: *
! 723: * Based largely in part to the example code contained in the document
! 724: * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written
! 725: * by Neal Nuckolls of SunSoft Internet Engineering.
! 726: *
! 727: * This code has been developed and tested on sparc-based machines running
! 728: * SunOS 5.5.1, with le and hme network interfaces. It should be pretty
! 729: * generic, though.
! 730: *
! 731: * The usual disclaimers apply. This code works for me. Don't blame me
! 732: * if it makes your machine or network go down in flames. That taken
! 733: * into consideration, use this code as you wish. If you make usefull
! 734: * modifications I'd appreciate hearing about it.
! 735: */
! 736:
! 737: #define DLPI_MAXWAIT 15 /* Max timeout */
! 738:
! 739:
! 740: /*
! 741: * Parse an interface name and extract the unit number
! 742: */
! 743:
! 744: static int dlpiunit (ifname)
! 745: char *ifname;
! 746: {
! 747: char *cp;
! 748: int unit;
! 749:
! 750: if (!ifname) {
! 751: return 0;
! 752: }
! 753:
! 754: /* Advance to the end of the name */
! 755: cp = ifname;
! 756: while (*cp) cp++;
! 757: /* Back up to the start of the first digit */
! 758: while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--;
! 759:
! 760: /* Convert the unit number */
! 761: unit = 0;
! 762: while (*cp >= '0' && *cp <= '9') {
! 763: unit *= 10;
! 764: unit += (*cp++ - '0');
! 765: }
! 766:
! 767: return unit;
! 768: }
! 769:
! 770: /*
! 771: * dlpiopen - open the DLPI device for a given interface name
! 772: */
! 773: static int
! 774: dlpiopen(const char *ifname) {
! 775: char devname [50];
! 776: char *dp;
! 777: const char *cp, *ep;
! 778:
! 779: if (!ifname) {
! 780: return -1;
! 781: }
! 782:
! 783: /* Open a DLPI device */
! 784: if (*ifname == '/') {
! 785: dp = devname;
! 786: } else {
! 787: /* Prepend the device directory */
! 788: memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR));
! 789: dp = &devname [strlen (DLPI_DEVDIR)];
! 790: }
! 791:
! 792: /* Find the end of the interface name */
! 793: ep = cp = ifname;
! 794: while (*ep)
! 795: ep++;
! 796: /* And back up to the first digit (unit number) */
! 797: while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':')
! 798: ep--;
! 799:
! 800: /* Copy everything up to the unit number */
! 801: while (cp < ep) {
! 802: *dp++ = *cp++;
! 803: }
! 804: *dp = '\0';
! 805:
! 806: return open (devname, O_RDWR, 0);
! 807: }
! 808:
! 809: /*
! 810: * dlpiinforeq - request information about the data link provider.
! 811: */
! 812:
! 813: static int dlpiinforeq (fd)
! 814: int fd;
! 815: {
! 816: dl_info_req_t info_req;
! 817: struct strbuf ctl;
! 818: int flags;
! 819:
! 820: info_req.dl_primitive = DL_INFO_REQ;
! 821:
! 822: ctl.maxlen = 0;
! 823: ctl.len = sizeof (info_req);
! 824: ctl.buf = (char *)&info_req;
! 825:
! 826: flags = RS_HIPRI;
! 827:
! 828: return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
! 829: }
! 830:
! 831: /*
! 832: * dlpiphysaddrreq - request the current physical address.
! 833: */
! 834: static int dlpiphysaddrreq (fd, addrtype)
! 835: int fd;
! 836: unsigned long addrtype;
! 837: {
! 838: dl_phys_addr_req_t physaddr_req;
! 839: struct strbuf ctl;
! 840: int flags;
! 841:
! 842: physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
! 843: physaddr_req.dl_addr_type = addrtype;
! 844:
! 845: ctl.maxlen = 0;
! 846: ctl.len = sizeof (physaddr_req);
! 847: ctl.buf = (char *)&physaddr_req;
! 848:
! 849: flags = RS_HIPRI;
! 850:
! 851: return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
! 852: }
! 853:
! 854: /*
! 855: * dlpiattachreq - send a request to attach to a specific unit.
! 856: */
! 857: static int dlpiattachreq (fd, ppa)
! 858: unsigned long ppa;
! 859: int fd;
! 860: {
! 861: dl_attach_req_t attach_req;
! 862: struct strbuf ctl;
! 863: int flags;
! 864:
! 865: attach_req.dl_primitive = DL_ATTACH_REQ;
! 866: attach_req.dl_ppa = ppa;
! 867:
! 868: ctl.maxlen = 0;
! 869: ctl.len = sizeof (attach_req);
! 870: ctl.buf = (char *)&attach_req;
! 871:
! 872: flags = 0;
! 873:
! 874: return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
! 875: }
! 876:
! 877: /*
! 878: * dlpibindreq - send a request to bind to a specific SAP address.
! 879: */
! 880: static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
! 881: unsigned long sap;
! 882: unsigned long max_conind;
! 883: unsigned long service_mode;
! 884: unsigned long conn_mgmt;
! 885: unsigned long xidtest;
! 886: int fd;
! 887: {
! 888: dl_bind_req_t bind_req;
! 889: struct strbuf ctl;
! 890: int flags;
! 891:
! 892: bind_req.dl_primitive = DL_BIND_REQ;
! 893: bind_req.dl_sap = sap;
! 894: bind_req.dl_max_conind = max_conind;
! 895: bind_req.dl_service_mode = service_mode;
! 896: bind_req.dl_conn_mgmt = conn_mgmt;
! 897: bind_req.dl_xidtest_flg = xidtest;
! 898:
! 899: ctl.maxlen = 0;
! 900: ctl.len = sizeof (bind_req);
! 901: ctl.buf = (char *)&bind_req;
! 902:
! 903: flags = 0;
! 904:
! 905: return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
! 906: }
! 907:
! 908: #if defined(UNUSED_DLPI_INTERFACE)
! 909: /*
! 910: * dlpiunbindreq - send a request to unbind. This function is not actually
! 911: * used by ISC DHCP, but is included for completeness in case it is
! 912: * ever required for new work.
! 913: */
! 914: static int dlpiunbindreq (fd)
! 915: int fd;
! 916: {
! 917: dl_unbind_req_t unbind_req;
! 918: struct strbuf ctl;
! 919: int flags;
! 920:
! 921: unbind_req.dl_primitive = DL_UNBIND_REQ;
! 922:
! 923: ctl.maxlen = 0;
! 924: ctl.len = sizeof (unbind_req);
! 925: ctl.buf = (char *)&unbind_req;
! 926:
! 927: flags = 0;
! 928:
! 929: return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
! 930: }
! 931:
! 932:
! 933: /*
! 934: * dlpidetachreq - send a request to detach. This function is not actually
! 935: * used by ISC DHCP, but is included for completeness in case it is
! 936: * ever required for new work.
! 937: */
! 938: static int dlpidetachreq (fd)
! 939: int fd;
! 940: {
! 941: dl_detach_req_t detach_req;
! 942: struct strbuf ctl;
! 943: int flags;
! 944:
! 945: detach_req.dl_primitive = DL_DETACH_REQ;
! 946:
! 947: ctl.maxlen = 0;
! 948: ctl.len = sizeof (detach_req);
! 949: ctl.buf = (char *)&detach_req;
! 950:
! 951: flags = 0;
! 952:
! 953: return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
! 954: }
! 955: #endif /* UNUSED_DLPI_INTERFACE */
! 956:
! 957:
! 958: /*
! 959: * dlpibindack - receive an ack to a dlbindreq.
! 960: */
! 961: static int dlpibindack (fd, bufp)
! 962: char *bufp;
! 963: int fd;
! 964: {
! 965: union DL_primitives *dlp;
! 966: struct strbuf ctl;
! 967: int flags;
! 968:
! 969: ctl.maxlen = DLPI_MAXDLBUF;
! 970: ctl.len = 0;
! 971: ctl.buf = bufp;
! 972:
! 973: if (strgetmsg (fd, &ctl,
! 974: (struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
! 975: return -1;
! 976: }
! 977:
! 978: dlp = (union DL_primitives *)ctl.buf;
! 979:
! 980: if (expected (DL_BIND_ACK, dlp, flags) == -1) {
! 981: return -1;
! 982: }
! 983:
! 984: if (ctl.len < sizeof (dl_bind_ack_t)) {
! 985: /* Returned structure is too short */
! 986: return -1;
! 987: }
! 988:
! 989: return 0;
! 990: }
! 991:
! 992: /*
! 993: * dlpiokack - general acknowledgement reception.
! 994: */
! 995: static int dlpiokack (fd, bufp)
! 996: char *bufp;
! 997: int fd;
! 998: {
! 999: union DL_primitives *dlp;
! 1000: struct strbuf ctl;
! 1001: int flags;
! 1002:
! 1003: ctl.maxlen = DLPI_MAXDLBUF;
! 1004: ctl.len = 0;
! 1005: ctl.buf = bufp;
! 1006:
! 1007: if (strgetmsg (fd, &ctl,
! 1008: (struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
! 1009: return -1;
! 1010: }
! 1011:
! 1012: dlp = (union DL_primitives *)ctl.buf;
! 1013:
! 1014: if (expected (DL_OK_ACK, dlp, flags) == -1) {
! 1015: return -1;
! 1016: }
! 1017:
! 1018: if (ctl.len < sizeof (dl_ok_ack_t)) {
! 1019: /* Returned structure is too short */
! 1020: return -1;
! 1021: }
! 1022:
! 1023: return 0;
! 1024: }
! 1025:
! 1026: /*
! 1027: * dlpiinfoack - receive an ack to a dlinforeq.
! 1028: */
! 1029: static int dlpiinfoack (fd, bufp)
! 1030: char *bufp;
! 1031: int fd;
! 1032: {
! 1033: union DL_primitives *dlp;
! 1034: struct strbuf ctl;
! 1035: int flags;
! 1036:
! 1037: ctl.maxlen = DLPI_MAXDLBUF;
! 1038: ctl.len = 0;
! 1039: ctl.buf = bufp;
! 1040:
! 1041: if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
! 1042: "dlpiinfoack") < 0) {
! 1043: return -1;
! 1044: }
! 1045:
! 1046: dlp = (union DL_primitives *) ctl.buf;
! 1047:
! 1048: if (expected (DL_INFO_ACK, dlp, flags) == -1) {
! 1049: return -1;
! 1050: }
! 1051:
! 1052: if (ctl.len < sizeof (dl_info_ack_t)) {
! 1053: /* Returned structure is too short */
! 1054: return -1;
! 1055: }
! 1056:
! 1057: return 0;
! 1058: }
! 1059:
! 1060: /*
! 1061: * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
! 1062: */
! 1063: int dlpiphysaddrack (fd, bufp)
! 1064: char *bufp;
! 1065: int fd;
! 1066: {
! 1067: union DL_primitives *dlp;
! 1068: struct strbuf ctl;
! 1069: int flags;
! 1070:
! 1071: ctl.maxlen = DLPI_MAXDLBUF;
! 1072: ctl.len = 0;
! 1073: ctl.buf = bufp;
! 1074:
! 1075: if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
! 1076: "dlpiphysaddrack") < 0) {
! 1077: return -1;
! 1078: }
! 1079:
! 1080: dlp = (union DL_primitives *)ctl.buf;
! 1081:
! 1082: if (expected (DL_PHYS_ADDR_ACK, dlp, flags) == -1) {
! 1083: return -1;
! 1084: }
! 1085:
! 1086: if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
! 1087: /* Returned structure is too short */
! 1088: return -1;
! 1089: }
! 1090:
! 1091: return 0;
! 1092: }
! 1093:
! 1094: #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE)
! 1095: int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen)
! 1096: int fd;
! 1097: unsigned char *addr;
! 1098: int addrlen;
! 1099: unsigned long minpri;
! 1100: unsigned long maxpri;
! 1101: unsigned char *dbuf;
! 1102: int dbuflen;
! 1103: {
! 1104: long buf [DLPI_MAXDLBUF];
! 1105: union DL_primitives *dlp;
! 1106: struct strbuf ctl, data;
! 1107:
! 1108: /* Set up the control information... */
! 1109: dlp = (union DL_primitives *)buf;
! 1110: dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ;
! 1111: dlp -> unitdata_req.dl_dest_addr_length = addrlen;
! 1112: dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
! 1113: dlp -> unitdata_req.dl_priority.dl_min = minpri;
! 1114: dlp -> unitdata_req.dl_priority.dl_max = maxpri;
! 1115:
! 1116: /* Append the destination address */
! 1117: memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
! 1118: addr, addrlen);
! 1119:
! 1120: ctl.maxlen = 0;
! 1121: ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
! 1122: ctl.buf = (char *)buf;
! 1123:
! 1124: data.maxlen = 0;
! 1125: data.buf = (char *)dbuf;
! 1126: data.len = dbuflen;
! 1127:
! 1128: /* Send the packet down the wire... */
! 1129: return putmsg (fd, &ctl, &data, 0);
! 1130: }
! 1131:
! 1132: static int dlpiunitdataind (fd, daddr, daddrlen,
! 1133: saddr, saddrlen, grpaddr, dbuf, dlen)
! 1134: int fd;
! 1135: unsigned char *daddr;
! 1136: unsigned long *daddrlen;
! 1137: unsigned char *saddr;
! 1138: unsigned long *saddrlen;
! 1139: unsigned long *grpaddr;
! 1140: unsigned char *dbuf;
! 1141: int dlen;
! 1142: {
! 1143: long buf [DLPI_MAXDLBUF];
! 1144: union DL_primitives *dlp;
! 1145: struct strbuf ctl, data;
! 1146: int flags = 0;
! 1147: int result;
! 1148:
! 1149: /* Set up the msg_buf structure... */
! 1150: dlp = (union DL_primitives *)buf;
! 1151: dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
! 1152:
! 1153: ctl.maxlen = DLPI_MAXDLBUF;
! 1154: ctl.len = 0;
! 1155: ctl.buf = (char *)buf;
! 1156:
! 1157: data.maxlen = dlen;
! 1158: data.len = 0;
! 1159: data.buf = (char *)dbuf;
! 1160:
! 1161: result = getmsg (fd, &ctl, &data, &flags);
! 1162:
! 1163: if (result < 0) {
! 1164: log_debug("dlpiunitdataind: %m");
! 1165: return -1;
! 1166: }
! 1167:
! 1168: if (ctl.len < sizeof (dl_unitdata_ind_t) ||
! 1169: dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
! 1170: return -1;
! 1171: }
! 1172:
! 1173: if (data.len <= 0) {
! 1174: return data.len;
! 1175: }
! 1176:
! 1177: /* Copy sender info */
! 1178: if (saddr) {
! 1179: memcpy (saddr,
! 1180: (char *)buf + dlp -> unitdata_ind.dl_src_addr_offset,
! 1181: dlp -> unitdata_ind.dl_src_addr_length);
! 1182: }
! 1183: if (saddrlen) {
! 1184: *saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
! 1185: }
! 1186:
! 1187: /* Copy destination info */
! 1188: if (daddr) {
! 1189: memcpy (daddr,
! 1190: (char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset,
! 1191: dlp -> unitdata_ind.dl_dest_addr_length);
! 1192: }
! 1193: if (daddrlen) {
! 1194: *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
! 1195: }
! 1196:
! 1197: if (grpaddr) {
! 1198: *grpaddr = dlp -> unitdata_ind.dl_group_address;
! 1199: }
! 1200:
! 1201: return data.len;
! 1202: }
! 1203: #endif /* !USE_DLPI_HWADDR: USE_DLPI_RECEIVE || USE_DLPI_SEND */
! 1204:
! 1205: /*
! 1206: * expected - see if we got what we wanted.
! 1207: */
! 1208: static int expected (prim, dlp, msgflags)
! 1209: unsigned long prim;
! 1210: union DL_primitives *dlp;
! 1211: int msgflags;
! 1212: {
! 1213: if (msgflags != RS_HIPRI) {
! 1214: /* Message was not M_PCPROTO */
! 1215: return -1;
! 1216: }
! 1217:
! 1218: if (dlp->dl_primitive != prim) {
! 1219: /* Incorrect/unexpected return message */
! 1220: return -1;
! 1221: }
! 1222:
! 1223: return 0;
! 1224: }
! 1225:
! 1226: /*
! 1227: * strgetmsg - get a message from a stream, with timeout.
! 1228: */
! 1229: static int strgetmsg (fd, ctlp, datap, flagsp, caller)
! 1230: struct strbuf *ctlp, *datap;
! 1231: char *caller;
! 1232: int *flagsp;
! 1233: int fd;
! 1234: {
! 1235: int result;
! 1236: struct pollfd pfd;
! 1237: int count;
! 1238: time_t now;
! 1239: time_t starttime;
! 1240: int to_msec;
! 1241:
! 1242: pfd.fd = fd;
! 1243: pfd.events = POLLPRI; /* We're only interested in knowing
! 1244: * when we can receive the next high
! 1245: * priority message.
! 1246: */
! 1247: pfd.revents = 0;
! 1248:
! 1249: now = time (&starttime);
! 1250: while (now <= starttime + DLPI_MAXWAIT) {
! 1251: to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000;
! 1252: count = poll (&pfd, 1, to_msec);
! 1253:
! 1254: if (count == 0) {
! 1255: /* log_fatal ("strgetmsg: timeout"); */
! 1256: return -1;
! 1257: } else if (count < 0) {
! 1258: if (errno == EAGAIN || errno == EINTR) {
! 1259: time (&now);
! 1260: continue;
! 1261: } else {
! 1262: /* log_fatal ("poll: %m"); */
! 1263: return -1;
! 1264: }
! 1265: } else {
! 1266: break;
! 1267: }
! 1268: }
! 1269:
! 1270: /*
! 1271: * Set flags argument and issue getmsg ().
! 1272: */
! 1273: *flagsp = 0;
! 1274: if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
! 1275: return result;
! 1276: }
! 1277:
! 1278: /*
! 1279: * Check for MOREDATA and/or MORECTL.
! 1280: */
! 1281: if (result & (MORECTL|MOREDATA)) {
! 1282: return -1;
! 1283: }
! 1284:
! 1285: /*
! 1286: * Check for at least sizeof (long) control data portion.
! 1287: */
! 1288: if (ctlp -> len < sizeof (long)) {
! 1289: return -1;
! 1290: }
! 1291:
! 1292: return 0;
! 1293: }
! 1294:
! 1295: #if defined(USE_DLPI_SEND)
! 1296: int can_unicast_without_arp (ip)
! 1297: struct interface_info *ip;
! 1298: {
! 1299: return 1;
! 1300: }
! 1301:
! 1302: int can_receive_unicast_unconfigured (ip)
! 1303: struct interface_info *ip;
! 1304: {
! 1305: return 1;
! 1306: }
! 1307:
! 1308: int supports_multiple_interfaces (ip)
! 1309: struct interface_info *ip;
! 1310: {
! 1311: return 1;
! 1312: }
! 1313:
! 1314: void maybe_setup_fallback ()
! 1315: {
! 1316: isc_result_t status;
! 1317: struct interface_info *fbi = (struct interface_info *)0;
! 1318: if (setup_fallback (&fbi, MDL)) {
! 1319: if_register_fallback (fbi);
! 1320: status = omapi_register_io_object ((omapi_object_t *)fbi,
! 1321: if_readsocket, 0,
! 1322: fallback_discard, 0, 0);
! 1323: if (status != ISC_R_SUCCESS)
! 1324: log_fatal ("Can't register I/O handle for %s: %s",
! 1325: fbi -> name, isc_result_totext (status));
! 1326: interface_dereference (&fbi, MDL);
! 1327: }
! 1328: }
! 1329: #endif /* USE_DLPI_SEND */
! 1330:
! 1331: void
! 1332: get_hw_addr(const char *name, struct hardware *hw) {
! 1333: int sock, unit;
! 1334: long buf[DLPI_MAXDLBUF];
! 1335: union DL_primitives *dlp;
! 1336:
! 1337: dlp = (union DL_primitives *)buf;
! 1338:
! 1339: /*
! 1340: * Open a DLPI device.
! 1341: */
! 1342: sock = dlpiopen(name);
! 1343: if (sock < 0) {
! 1344: log_fatal("Can't open DLPI device for %s: %m", name);
! 1345: }
! 1346:
! 1347: /*
! 1348: * Submit a DL_INFO_REQ request, to find the dl_mac_type and
! 1349: * dl_provider_style
! 1350: */
! 1351: if (dlpiinforeq(sock) < 0) {
! 1352: log_fatal("Can't request DLPI MAC type for %s: %m", name);
! 1353: }
! 1354: if (dlpiinfoack(sock, (char *)buf) < 0) {
! 1355: log_fatal("Can't get DLPI MAC type for %s: %m", name);
! 1356: }
! 1357: switch (dlp->info_ack.dl_mac_type) {
! 1358: case DL_CSMACD: /* IEEE 802.3 */
! 1359: case DL_ETHER:
! 1360: hw->hbuf[0] = HTYPE_ETHER;
! 1361: break;
! 1362: case DL_TPR:
! 1363: hw->hbuf[0] = HTYPE_IEEE802;
! 1364: break;
! 1365: case DL_FDDI:
! 1366: hw->hbuf[0] = HTYPE_FDDI;
! 1367: break;
! 1368: default:
! 1369: log_fatal("%s: unsupported DLPI MAC type %lu", name,
! 1370: (unsigned long)dlp->info_ack.dl_mac_type);
! 1371: }
! 1372:
! 1373: if (dlp->info_ack.dl_provider_style == DL_STYLE2) {
! 1374: /*
! 1375: * Attach to the device. If this fails, the device
! 1376: * does not exist.
! 1377: */
! 1378: unit = dlpiunit((char *)name);
! 1379:
! 1380: if (dlpiattachreq(sock, unit) < 0 ||
! 1381: dlpiokack(sock, (char *)buf) < 0) {
! 1382: log_fatal("Can't attach DLPI device for %s: %m",
! 1383: name);
! 1384: }
! 1385: }
! 1386:
! 1387: /*
! 1388: * Submit a DL_PHYS_ADDR_REQ request, to find
! 1389: * the hardware address.
! 1390: */
! 1391: if (dlpiphysaddrreq(sock, DL_CURR_PHYS_ADDR) < 0) {
! 1392: log_fatal("Can't request DLPI hardware address for %s: %m",
! 1393: name);
! 1394: }
! 1395: if (dlpiphysaddrack(sock, (char *)buf) < 0) {
! 1396: log_fatal("Can't get DLPI hardware address for %s: %m",
! 1397: name);
! 1398: }
! 1399: if (dlp->physaddr_ack.dl_addr_length < sizeof(hw->hbuf)) {
! 1400: memcpy(hw->hbuf+1,
! 1401: (char *)buf + dlp->physaddr_ack.dl_addr_offset,
! 1402: dlp->physaddr_ack.dl_addr_length);
! 1403: hw->hlen = dlp->physaddr_ack.dl_addr_length + 1;
! 1404: } else {
! 1405: memcpy(hw->hbuf+1,
! 1406: (char *)buf + dlp->physaddr_ack.dl_addr_offset,
! 1407: sizeof(hw->hbuf)-1);
! 1408: hw->hlen = sizeof(hw->hbuf);
! 1409: }
! 1410:
! 1411: close(sock);
! 1412: }
! 1413: #endif /* USE_DLPI_SEND || USE_DLPI_RECEIVE || USE_DLPI_HWADDR */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>