diff options
Diffstat (limited to 'contrib/isc-dhcp/common/dlpi.c')
-rw-r--r-- | contrib/isc-dhcp/common/dlpi.c | 1336 |
1 files changed, 0 insertions, 1336 deletions
diff --git a/contrib/isc-dhcp/common/dlpi.c b/contrib/isc-dhcp/common/dlpi.c deleted file mode 100644 index 08e9764..0000000 --- a/contrib/isc-dhcp/common/dlpi.c +++ /dev/null @@ -1,1336 +0,0 @@ -/* dlpi.c - - Data Link Provider Interface (DLPI) network interface code. */ - -/* - * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1996-2003 by Internet Software Consortium - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Internet Systems Consortium, Inc. - * 950 Charter Street - * Redwood City, CA 94063 - * <info@isc.org> - * http://www.isc.org/ - * - * This software was written for Internet Systems Consortium - * by Eric James Negaard, <lmdejn@lmd.ericsson.se>. To learn more about - * Internet Systems Consortium, see ``http://www.isc.org''. - * - * Joost Mulders has also done considerable work in debugging the DLPI API - * support on Solaris and getting this code to work properly on a variety - * of different Solaris platforms. - */ - -/* - * Based largely in part to the existing NIT code in nit.c. - * - * This code has been developed and tested on sparc-based machines running - * SunOS 5.5.1, with le and hme network interfaces. It should be pretty - * generic, though. - */ - -/* - * Implementation notes: - * - * I first tried to write this code to the "vanilla" DLPI 2.0 API. - * It worked on a Sun Ultra-1 with a hme interface, but didn't work - * on Sun SparcStation 5's with "le" interfaces (the packets sent out - * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead - * of the expected 0x0800). - * - * Therefore I added the "DLPI_RAW" code which is a Sun extension to - * the DLPI standard. This code works on both of the above machines. - * This is configurable in the OS-dependent include file by defining - * USE_DLPI_RAW. - * - * It quickly became apparant that I should also use the "pfmod" - * STREAMS module to cut down on the amount of user level packet - * processing. I don't know how widely available "pfmod" is, so it's - * use is conditionally included. This is configurable in the - * OS-dependent include file by defining USE_DLPI_PFMOD. - * - * A major quirk on the Sun's at least, is that no packets seem to get - * sent out the interface until six seconds after the interface is - * first "attached" to [per system reboot] (it's actually from when - * the interface is attached, not when it is plumbed, so putting a - * sleep into the dhclient-script at PREINIT time doesn't help). I - * HAVE tried, without success to poll the fd to see when it is ready - * for writing. This doesn't help at all. If the sleeps are not done, - * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so - * I've put them here, when register_send and register_receive are - * called (split up into two three-second sleeps between the notices, - * so that it doesn't seem like so long when you're watching :-). The - * amount of time to sleep is configurable in the OS-dependent include - * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds - * to sleep. - */ - -#ifndef lint -static char copyright[] = -"$Id: dlpi.c,v 1.28.2.2 2004/06/10 17:59:17 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n"; -#endif /* not lint */ - -#include "dhcpd.h" - -#if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) - -# include <sys/ioctl.h> -# include <sys/time.h> -# include <sys/dlpi.h> -# include <stropts.h> -# ifdef USE_DLPI_PFMOD -# include <sys/pfmod.h> -# endif -# ifdef USE_POLL -# include <poll.h> -# endif - -# include <netinet/in_systm.h> -# include "includes/netinet/ip.h" -# include "includes/netinet/udp.h" -# include "includes/netinet/if_ether.h" - -# ifdef USE_DLPI_PFMOD -# ifdef USE_DLPI_RAW -# define DLPI_MODNAME "DLPI+RAW+PFMOD" -# else -# define DLPI_MODNAME "DLPI+PFMOD" -# endif -# else -# ifdef USE_DLPI_RAW -# define DLPI_MODNAME "DLPI+RAW" -# else -# define DLPI_MODNAME "DLPI" -# endif -# endif - -# ifndef ABS -# define ABS(x) ((x) >= 0 ? (x) : 0-(x)) -# endif - -static int strioctl PROTO ((int fd, int cmd, int timeout, int len, char *dp)); - -#define DLPI_MAXDLBUF 8192 /* Buffer size */ -#define DLPI_MAXDLADDR 1024 /* Max address size */ -#define DLPI_DEVDIR "/dev/" /* Device directory */ - -static int dlpiopen PROTO ((char *ifname)); -static int dlpiunit PROTO ((char *ifname)); -static int dlpiinforeq PROTO ((int fd)); -static int dlpiphysaddrreq PROTO ((int fd, unsigned long addrtype)); -static int dlpiattachreq PROTO ((int fd, unsigned long ppa)); -static int dlpibindreq PROTO ((int fd, unsigned long sap, unsigned long max_conind, - unsigned long service_mode, unsigned long conn_mgmt, - unsigned long xidtest)); -static int dlpidetachreq PROTO ((int fd)); -static int dlpiunbindreq PROTO ((int fd)); -static int dlpiokack PROTO ((int fd, char *bufp)); -static int dlpiinfoack PROTO ((int fd, char *bufp)); -static int dlpiphysaddrack PROTO ((int fd, char *bufp)); -static int dlpibindack PROTO ((int fd, char *bufp)); -static int dlpiunitdatareq PROTO ((int fd, unsigned char *addr, - int addrlen, unsigned long minpri, - unsigned long maxpri, unsigned char *data, - int datalen)); -static int dlpiunitdataind PROTO ((int fd, - unsigned char *dstaddr, - unsigned long *dstaddrlen, - unsigned char *srcaddr, - unsigned long *srcaddrlen, - unsigned long *grpaddr, - unsigned char *data, - int datalen)); - -# ifndef USE_POLL -static void sigalrm PROTO ((int sig)); -# endif -static int expected PROTO ((unsigned long prim, union DL_primitives *dlp, - int msgflags)); -static int strgetmsg PROTO ((int fd, struct strbuf *ctlp, - struct strbuf *datap, int *flagsp, - char *caller)); - -/* Reinitializes the specified interface after an address change. This - is not required for packet-filter APIs. */ - -#ifdef USE_DLPI_SEND -void if_reinitialize_send (info) - struct interface_info *info; -{ -} -#endif - -#ifdef USE_DLPI_RECEIVE -void if_reinitialize_receive (info) - struct interface_info *info; -{ -} -#endif - -/* Called by get_interface_list for each interface that's discovered. - Opens a packet filter for each interface and adds it to the select - mask. */ - -int if_register_dlpi (info) - struct interface_info *info; -{ - int sock; - int unit; - long buf [DLPI_MAXDLBUF]; - union DL_primitives *dlp; - - dlp = (union DL_primitives *)buf; - - /* Open a DLPI device */ - if ((sock = dlpiopen (info -> name)) < 0) { - log_fatal ("Can't open DLPI device for %s: %m", info -> name); - } - - - /* - * Submit a DL_INFO_REQ request, to find the dl_mac_type and - * dl_provider_style - */ - if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) { - log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name); - } else { - switch (dlp -> info_ack.dl_mac_type) { - case DL_CSMACD: /* IEEE 802.3 */ - case DL_ETHER: - info -> hw_address.hbuf [0] = HTYPE_ETHER; - break; - /* adding token ring 5/1999 - mayer@ping.at */ - case DL_TPR: - info -> hw_address.hbuf [0] = HTYPE_IEEE802; - break; - case DL_FDDI: - info -> hw_address.hbuf [0] = HTYPE_FDDI; - break; - default: - log_fatal ("%s: unsupported DLPI MAC type %ld", - info -> name, dlp -> info_ack.dl_mac_type); - break; - } - /* - * copy the sap length and broadcast address of this interface - * to interface_info. This fixes nothing but seemed nicer than to - * assume -2 and ffffff. - */ - info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length; - info -> dlpi_broadcast_addr.hlen = - dlp -> info_ack.dl_brdcst_addr_length; - memcpy (info -> dlpi_broadcast_addr.hbuf, - (char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset, - dlp -> info_ack.dl_brdcst_addr_length); - } - - if (dlp -> info_ack.dl_provider_style == DL_STYLE2) { - /* - * Attach to the device. If this fails, the device - * does not exist. - */ - unit = dlpiunit (info -> name); - - if (dlpiattachreq (sock, unit) < 0 - || dlpiokack (sock, (char *)buf) < 0) { - log_fatal ("Can't attach DLPI device for %s: %m", info -> name); - } - } - - /* - * Bind to the IP service access point (SAP), connectionless (CLDLS). - */ - if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0 - || dlpibindack (sock, (char *)buf) < 0) { - log_fatal ("Can't bind DLPI device for %s: %m", info -> name); - } - - /* - * Submit a DL_PHYS_ADDR_REQ request, to find - * the hardware address - */ - if (dlpiphysaddrreq (sock, DL_CURR_PHYS_ADDR) < 0 - || dlpiphysaddrack (sock, (char *)buf) < 0) { - log_fatal ("Can't get DLPI hardware address for %s: %m", - info -> name); - } - - info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1; - memcpy (&info -> hw_address.hbuf [1], - (char *)buf + dlp -> physaddr_ack.dl_addr_offset, - dlp -> physaddr_ack.dl_addr_length); - -#ifdef USE_DLPI_RAW - if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) { - log_fatal ("Can't set DLPI RAW mode for %s: %m", - info -> name); - } -#endif - -#ifdef USE_DLPI_PFMOD - if (ioctl (sock, I_PUSH, "pfmod") < 0) { - log_fatal ("Can't push packet filter onto DLPI for %s: %m", - info -> name); - } -#endif - - return sock; -} - -static int -strioctl (fd, cmd, timeout, len, dp) -int fd; -int cmd; -int timeout; -int len; -char *dp; -{ - struct strioctl sio; - int rslt; - - sio.ic_cmd = cmd; - sio.ic_timout = timeout; - sio.ic_len = len; - sio.ic_dp = dp; - - if ((rslt = ioctl (fd, I_STR, &sio)) < 0) { - return rslt; - } else { - return sio.ic_len; - } -} - -#ifdef USE_DLPI_SEND -void if_register_send (info) - struct interface_info *info; -{ - /* If we're using the DLPI API for sending and receiving, - we don't need to register this interface twice. */ -#ifndef USE_DLPI_RECEIVE -# ifdef USE_DLPI_PFMOD - struct packetfilt pf; -# endif - - info -> wfdesc = if_register_dlpi (info); - -# ifdef USE_DLPI_PFMOD - /* Set up an PFMOD filter that rejects everything... */ - pf.Pf_Priority = 0; - pf.Pf_FilterLen = 1; - pf.Pf_Filter [0] = ENF_PUSHZERO; - - /* Install the filter */ - if (strioctl (info -> wfdesc, PFIOCSETF, INFTIM, - sizeof (pf), (char *)&pf) < 0) { - log_fatal ("Can't set PFMOD send filter on %s: %m", info -> name); - } - -# endif /* USE_DLPI_PFMOD */ -#else /* !defined (USE_DLPI_RECEIVE) */ - /* - * If using DLPI for both send and receive, simply re-use - * the read file descriptor that was set up earlier. - */ - info -> wfdesc = info -> rfdesc; -#endif - - if (!quiet_interface_discovery) - log_info ("Sending on DLPI/%s/%s%s%s", - info -> name, - print_hw_addr (info -> hw_address.hbuf [0], - info -> hw_address.hlen - 1, - &info -> hw_address.hbuf [1]), - (info -> shared_network ? "/" : ""), - (info -> shared_network ? - info -> shared_network -> name : "")); - -#ifdef DLPI_FIRST_SEND_WAIT -/* See the implementation notes at the beginning of this file */ -# ifdef USE_DLPI_RECEIVE - sleep (DLPI_FIRST_SEND_WAIT - (DLPI_FIRST_SEND_WAIT / 2)); -# else - sleep (DLPI_FIRST_SEND_WAIT); -# endif -#endif -} - -void if_deregister_send (info) - struct interface_info *info; -{ - /* If we're using the DLPI API for sending and receiving, - we don't need to register this interface twice. */ -#ifndef USE_DLPI_RECEIVE - close (info -> wfdesc); -#endif - info -> wfdesc = -1; - - if (!quiet_interface_discovery) - log_info ("Disabling output on DLPI/%s/%s%s%s", - info -> name, - print_hw_addr (info -> hw_address.hbuf [0], - info -> hw_address.hlen - 1, - &info -> hw_address.hbuf [1]), - (info -> shared_network ? "/" : ""), - (info -> shared_network ? - info -> shared_network -> name : "")); -} -#endif /* USE_DLPI_SEND */ - -#ifdef USE_DLPI_RECEIVE -/* Packet filter program... - XXX Changes to the filter program may require changes to the constant - offsets used in if_register_send to patch the NIT program! XXX */ - -void if_register_receive (info) - struct interface_info *info; -{ -#ifdef USE_DLPI_PFMOD - struct packetfilt pf; - struct ip iphdr; - u_int16_t offset; -#endif - - /* Open a DLPI device and hang it on this interface... */ - info -> rfdesc = if_register_dlpi (info); - -#ifdef USE_DLPI_PFMOD - /* Set up the PFMOD filter program. */ - /* XXX Unlike the BPF filter program, this one won't work if the - XXX IP packet is fragmented or if there are options on the IP - XXX header. */ - pf.Pf_Priority = 0; - pf.Pf_FilterLen = 0; - -#if defined (USE_DLPI_RAW) -# define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */ - /* - * ethertype == ETHERTYPE_IP - */ - offset = 12; - pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); - pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; - pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP); -# else -# define ETHER_H_PREFIX (0) -# endif /* USE_DLPI_RAW */ - /* - * The packets that will be received on this file descriptor - * will be IP packets (due to the SAP that was specified in - * the dlbind call). There will be no ethernet header. - * Therefore, setup the packet filter to check the protocol - * field for UDP, and the destination port number equal - * to the local port. All offsets are relative to the start - * of an IP packet. - */ - - /* - * BOOTPS destination port - */ - offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t); - pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); - pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; - pf.Pf_Filter [pf.Pf_FilterLen++] = local_port; - - /* - * protocol should be udp. this is a byte compare, test for - * endianess. - */ - offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *)&iphdr); - pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); - pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND; - pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF); - pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; - pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP); - - /* Install the filter... */ - if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM, - sizeof (pf), (char *)&pf) < 0) { - log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name); - } -#endif /* USE_DLPI_PFMOD */ - - if (!quiet_interface_discovery) - log_info ("Listening on DLPI/%s/%s%s%s", - info -> name, - print_hw_addr (info -> hw_address.hbuf [0], - info -> hw_address.hlen - 1, - &info -> hw_address.hbuf [1]), - (info -> shared_network ? "/" : ""), - (info -> shared_network ? - info -> shared_network -> name : "")); - -#ifdef DLPI_FIRST_SEND_WAIT -/* See the implementation notes at the beginning of this file */ -# ifdef USE_DLPI_SEND - sleep (DLPI_FIRST_SEND_WAIT / 2); -# else - sleep (DLPI_FIRST_SEND_WAIT); -# endif -#endif -} - -void if_deregister_receive (info) - struct interface_info *info; -{ - /* If we're using the DLPI API for sending and receiving, - we don't need to register this interface twice. */ -#ifndef USE_DLPI_SEND - close (info -> rfdesc); -#endif - info -> rfdesc = -1; - - if (!quiet_interface_discovery) - log_info ("Disabling input on DLPI/%s/%s%s%s", - info -> name, - print_hw_addr (info -> hw_address.hbuf [0], - info -> hw_address.hlen - 1, - &info -> hw_address.hbuf [1]), - (info -> shared_network ? "/" : ""), - (info -> shared_network ? - info -> shared_network -> name : "")); -} -#endif /* USE_DLPI_RECEIVE */ - -#ifdef USE_DLPI_SEND -ssize_t send_packet (interface, packet, raw, len, from, to, hto) - struct interface_info *interface; - struct packet *packet; - struct dhcp_packet *raw; - size_t len; - struct in_addr from; - struct sockaddr_in *to; - struct hardware *hto; -{ - unsigned hbufp = 0; - double hh [32]; - double ih [1536 / sizeof (double)]; - unsigned char *dbuf = (unsigned char *)ih; - unsigned dbuflen; - unsigned char dstaddr [DLPI_MAXDLADDR]; - unsigned addrlen; - int result; - int fudge; - - if (!strcmp (interface -> name, "fallback")) - return send_fallback (interface, packet, raw, - len, from, to, hto); - - dbuflen = 0; - - /* Assemble the headers... */ -#ifdef USE_DLPI_RAW - assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto); - if (dbuflen > sizeof hh) - log_fatal ("send_packet: hh buffer too small.\n"); - fudge = dbuflen % 4; /* IP header must be word-aligned. */ - memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen); - dbuflen += fudge; -#else - fudge = 0; -#endif - assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr, - to -> sin_addr.s_addr, to -> sin_port, - (unsigned char *)raw, len); - - /* Copy the data into the buffer (yuk). */ - memcpy (dbuf + dbuflen, raw, len); - dbuflen += len; - -#ifdef USE_DLPI_RAW - result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge); -#else - - /* - * Setup the destination address (DLSAP) in dstaddr - * - * If sap_length < 0 we must deliver the DLSAP as phys+sap. - * If sap_length > 0 we must deliver the DLSAP as sap+phys. - * - * sap = Service Access Point == ETHERTYPE_IP - * sap + datalink address is called DLSAP in dlpi speak. - */ - { /* ENCODE DLSAP */ - unsigned char phys [DLPI_MAXDLADDR]; - unsigned char sap [4]; - int sap_len = interface -> dlpi_sap_length; - int phys_len = interface -> hw_address.hlen - 1; - - /* sap = htons (ETHERTYPE_IP) kludge */ - memset (sap, 0, sizeof (sap)); -# if (BYTE_ORDER == LITTLE_ENDIAN) - sap [0] = 0x00; - sap [1] = 0x08; -# else - sap [0] = 0x08; - sap [1] = 0x00; -# endif - - if (hto && hto -> hlen == interface -> hw_address.hlen) - memcpy ( phys, (char *) &hto -> hbuf [1], phys_len); - else - memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf, - interface -> dlpi_broadcast_addr.hlen); - - if (sap_len < 0) { - memcpy ( dstaddr, phys, phys_len); - memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len)); - } - else { - memcpy ( dstaddr, (void *) sap, sap_len); - memcpy ( (char *) &dstaddr [sap_len], phys, phys_len); - } - addrlen = phys_len + ABS (sap_len); - } /* ENCODE DLSAP */ - - result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen, - 0, 0, dbuf, dbuflen); -#endif /* USE_DLPI_RAW */ - if (result < 0) - log_error ("send_packet: %m"); - return result; -} -#endif /* USE_DLPI_SEND */ - -#ifdef USE_DLPI_RECEIVE -ssize_t receive_packet (interface, buf, len, from, hfrom) - struct interface_info *interface; - unsigned char *buf; - size_t len; - struct sockaddr_in *from; - struct hardware *hfrom; -{ - unsigned char dbuf [1536]; - unsigned char srcaddr [DLPI_MAXDLADDR]; - unsigned long srcaddrlen; - int flags = 0; - int length = 0; - int offset = 0; - int rslt; - int bufix = 0; - -#ifdef USE_DLPI_RAW - length = read (interface -> rfdesc, dbuf, sizeof (dbuf)); -#else - length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL, - (unsigned long *)NULL, srcaddr, &srcaddrlen, - (unsigned long *)NULL, dbuf, sizeof (dbuf)); -#endif - - if (length <= 0) { - return length; - } - -# if !defined (USE_DLPI_RAW) - /* - * Copy the sender's hw address into hfrom - * If sap_len < 0 the DLSAP is as phys+sap. - * If sap_len > 0 the DLSAP is as sap+phys. - * - * sap is discarded here. - */ - { /* DECODE DLSAP */ - int sap_len = interface -> dlpi_sap_length; - int phys_len = interface -> hw_address.hlen - 1; - - if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) { - hfrom -> hbuf [0] = interface -> hw_address.hbuf [0]; - hfrom -> hlen = interface -> hw_address.hlen; - - if (sap_len < 0) { - memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len); - } - else { - memcpy ((char *) &hfrom -> hbuf [1], (char *) &srcaddr [phys_len], - phys_len); - } - } - else if (hfrom) { - memset (hfrom, '\0', sizeof *hfrom); - } - } /* DECODE_DLSAP */ - -# endif /* !defined (USE_DLPI_RAW) */ - - /* Decode the IP and UDP headers... */ - bufix = 0; -#ifdef USE_DLPI_RAW - /* Decode the physical header... */ - offset = decode_hw_header (interface, dbuf, bufix, hfrom); - - /* If a physical layer checksum failed (dunno of any - physical layer that supports this, but WTH), skip this - packet. */ - if (offset < 0) { - return 0; - } - bufix += offset; - length -= offset; -#endif - offset = decode_udp_ip_header (interface, dbuf, bufix, - from, (unsigned char *)0, length); - - /* If the IP or UDP checksum was bad, skip the packet... */ - if (offset < 0) { - return 0; - } - - bufix += offset; - length -= offset; - - /* Copy out the data in the packet... */ - memcpy (buf, &dbuf [bufix], length); - return length; -} -#endif - -/* Common DLPI routines ... - * - * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se> - * - * Based largely in part to the example code contained in the document - * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written - * by Neal Nuckolls of SunSoft Internet Engineering. - * - * This code has been developed and tested on sparc-based machines running - * SunOS 5.5.1, with le and hme network interfaces. It should be pretty - * generic, though. - * - * The usual disclaimers apply. This code works for me. Don't blame me - * if it makes your machine or network go down in flames. That taken - * into consideration, use this code as you wish. If you make usefull - * modifications I'd appreciate hearing about it. - */ - -#define DLPI_MAXWAIT 15 /* Max timeout */ - - -/* - * Parse an interface name and extract the unit number - */ - -static int dlpiunit (ifname) - char *ifname; -{ - int fd; - char *cp, *dp, *ep; - int unit; - - if (!ifname) { - return 0; - } - - /* Advance to the end of the name */ - cp = ifname; - while (*cp) cp++; - /* Back up to the start of the first digit */ - while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--; - - /* Convert the unit number */ - unit = 0; - while (*cp >= '0' && *cp <= '9') { - unit *= 10; - unit += (*cp++ - '0'); - } - - return unit; -} - -/* - * dlpiopen - open the DLPI device for a given interface name - */ -static int dlpiopen (ifname) - char *ifname; -{ - char devname [50]; - char *cp, *dp, *ep; - - if (!ifname) { - return -1; - } - - /* Open a DLPI device */ - if (*ifname == '/') { - dp = devname; - } else { - /* Prepend the device directory */ - memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR)); - dp = &devname [strlen (DLPI_DEVDIR)]; - } - - /* Find the end of the interface name */ - ep = cp = ifname; - while (*ep) - ep++; - /* And back up to the first digit (unit number) */ - while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':') - ep--; - - /* Copy everything up to the unit number */ - while (cp < ep) { - *dp++ = *cp++; - } - *dp = '\0'; - - return open (devname, O_RDWR, 0); -} - -/* - * dlpiinforeq - request information about the data link provider. - */ - -static int dlpiinforeq (fd) - int fd; -{ - dl_info_req_t info_req; - struct strbuf ctl; - int flags; - - info_req.dl_primitive = DL_INFO_REQ; - - ctl.maxlen = 0; - ctl.len = sizeof (info_req); - ctl.buf = (char *)&info_req; - - flags = RS_HIPRI; - - return putmsg (fd, &ctl, (struct strbuf *)NULL, flags); -} - -/* - * dlpiphysaddrreq - request the current physical address. - */ -static int dlpiphysaddrreq (fd, addrtype) - int fd; - unsigned long addrtype; -{ - dl_phys_addr_req_t physaddr_req; - struct strbuf ctl; - int flags; - - physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ; - physaddr_req.dl_addr_type = addrtype; - - ctl.maxlen = 0; - ctl.len = sizeof (physaddr_req); - ctl.buf = (char *)&physaddr_req; - - flags = RS_HIPRI; - - return putmsg (fd, &ctl, (struct strbuf *)NULL, flags); -} - -/* - * dlpiattachreq - send a request to attach to a specific unit. - */ -static int dlpiattachreq (fd, ppa) - unsigned long ppa; - int fd; -{ - dl_attach_req_t attach_req; - struct strbuf ctl; - int flags; - - attach_req.dl_primitive = DL_ATTACH_REQ; - attach_req.dl_ppa = ppa; - - ctl.maxlen = 0; - ctl.len = sizeof (attach_req); - ctl.buf = (char *)&attach_req; - - flags = 0; - - return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); -} - -/* - * dlpibindreq - send a request to bind to a specific SAP address. - */ -static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest) - unsigned long sap; - unsigned long max_conind; - unsigned long service_mode; - unsigned long conn_mgmt; - unsigned long xidtest; - int fd; -{ - dl_bind_req_t bind_req; - struct strbuf ctl; - int flags; - - bind_req.dl_primitive = DL_BIND_REQ; - bind_req.dl_sap = sap; - bind_req.dl_max_conind = max_conind; - bind_req.dl_service_mode = service_mode; - bind_req.dl_conn_mgmt = conn_mgmt; - bind_req.dl_xidtest_flg = xidtest; - - ctl.maxlen = 0; - ctl.len = sizeof (bind_req); - ctl.buf = (char *)&bind_req; - - flags = 0; - - return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); -} - -/* - * dlpiunbindreq - send a request to unbind. - */ -static int dlpiunbindreq (fd) - int fd; -{ - dl_unbind_req_t unbind_req; - struct strbuf ctl; - int flags; - - unbind_req.dl_primitive = DL_UNBIND_REQ; - - ctl.maxlen = 0; - ctl.len = sizeof (unbind_req); - ctl.buf = (char *)&unbind_req; - - flags = 0; - - return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); -} - - -/* - * dlpidetachreq - send a request to detach. - */ -static int dlpidetachreq (fd) - int fd; -{ - dl_detach_req_t detach_req; - struct strbuf ctl; - int flags; - - detach_req.dl_primitive = DL_DETACH_REQ; - - ctl.maxlen = 0; - ctl.len = sizeof (detach_req); - ctl.buf = (char *)&detach_req; - - flags = 0; - - return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); -} - - -/* - * dlpibindack - receive an ack to a dlbindreq. - */ -static int dlpibindack (fd, bufp) - char *bufp; - int fd; -{ - union DL_primitives *dlp; - struct strbuf ctl; - int flags; - - ctl.maxlen = DLPI_MAXDLBUF; - ctl.len = 0; - ctl.buf = bufp; - - if (strgetmsg (fd, &ctl, - (struct strbuf*)NULL, &flags, "dlpibindack") < 0) { - return -1; - } - - dlp = (union DL_primitives *)ctl.buf; - - if (!expected (DL_BIND_ACK, dlp, flags) < 0) { - return -1; - } - - if (ctl.len < sizeof (dl_bind_ack_t)) { - /* Returned structure is too short */ - return -1; - } - - return 0; -} - -/* - * dlpiokack - general acknowledgement reception. - */ -static int dlpiokack (fd, bufp) - char *bufp; - int fd; -{ - union DL_primitives *dlp; - struct strbuf ctl; - int flags; - - ctl.maxlen = DLPI_MAXDLBUF; - ctl.len = 0; - ctl.buf = bufp; - - if (strgetmsg (fd, &ctl, - (struct strbuf*)NULL, &flags, "dlpiokack") < 0) { - return -1; - } - - dlp = (union DL_primitives *)ctl.buf; - - if (!expected (DL_OK_ACK, dlp, flags) < 0) { - return -1; - } - - if (ctl.len < sizeof (dl_ok_ack_t)) { - /* Returned structure is too short */ - return -1; - } - - return 0; -} - -/* - * dlpiinfoack - receive an ack to a dlinforeq. - */ -static int dlpiinfoack (fd, bufp) - char *bufp; - int fd; -{ - union DL_primitives *dlp; - struct strbuf ctl; - int flags; - - ctl.maxlen = DLPI_MAXDLBUF; - ctl.len = 0; - ctl.buf = bufp; - - if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags, - "dlpiinfoack") < 0) { - return -1; - } - - dlp = (union DL_primitives *) ctl.buf; - - if (!expected (DL_INFO_ACK, dlp, flags) < 0) { - return -1; - } - - if (ctl.len < sizeof (dl_info_ack_t)) { - /* Returned structure is too short */ - return -1; - } - - return 0; -} - -/* - * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq. - */ -int dlpiphysaddrack (fd, bufp) - char *bufp; - int fd; -{ - union DL_primitives *dlp; - struct strbuf ctl; - int flags; - - ctl.maxlen = DLPI_MAXDLBUF; - ctl.len = 0; - ctl.buf = bufp; - - if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags, - "dlpiphysaddrack") < 0) { - return -1; - } - - dlp = (union DL_primitives *)ctl.buf; - - if (!expected (DL_PHYS_ADDR_ACK, dlp, flags) < 0) { - return -1; - } - - if (ctl.len < sizeof (dl_phys_addr_ack_t)) { - /* Returned structure is too short */ - return -1; - } - - return 0; -} - -int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen) - int fd; - unsigned char *addr; - int addrlen; - unsigned long minpri; - unsigned long maxpri; - unsigned char *dbuf; - int dbuflen; -{ - long buf [DLPI_MAXDLBUF]; - union DL_primitives *dlp; - struct strbuf ctl, data; - - /* Set up the control information... */ - dlp = (union DL_primitives *)buf; - dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ; - dlp -> unitdata_req.dl_dest_addr_length = addrlen; - dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t); - dlp -> unitdata_req.dl_priority.dl_min = minpri; - dlp -> unitdata_req.dl_priority.dl_max = maxpri; - - /* Append the destination address */ - memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset, - addr, addrlen); - - ctl.maxlen = 0; - ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen; - ctl.buf = (char *)buf; - - data.maxlen = 0; - data.buf = (char *)dbuf; - data.len = dbuflen; - - /* Send the packet down the wire... */ - return putmsg (fd, &ctl, &data, 0); -} - -static int dlpiunitdataind (fd, daddr, daddrlen, - saddr, saddrlen, grpaddr, dbuf, dlen) - int fd; - unsigned char *daddr; - unsigned long *daddrlen; - unsigned char *saddr; - unsigned long *saddrlen; - unsigned long *grpaddr; - unsigned char *dbuf; - int dlen; -{ - long buf [DLPI_MAXDLBUF]; - union DL_primitives *dlp; - struct strbuf ctl, data; - int flags = 0; - int result; - - /* Set up the msg_buf structure... */ - dlp = (union DL_primitives *)buf; - dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND; - - ctl.maxlen = DLPI_MAXDLBUF; - ctl.len = 0; - ctl.buf = (char *)buf; - - data.maxlen = dlen; - data.len = 0; - data.buf = (char *)dbuf; - - result = getmsg (fd, &ctl, &data, &flags); - - if (result != 0) { - return -1; - } - - if (ctl.len < sizeof (dl_unitdata_ind_t) || - dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) { - return -1; - } - - if (data.len <= 0) { - return data.len; - } - - /* Copy sender info */ - if (saddr) { - memcpy (saddr, - (char *)buf + dlp -> unitdata_ind.dl_src_addr_offset, - dlp -> unitdata_ind.dl_src_addr_length); - } - if (saddrlen) { - *saddrlen = dlp -> unitdata_ind.dl_src_addr_length; - } - - /* Copy destination info */ - if (daddr) { - memcpy (daddr, - (char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset, - dlp -> unitdata_ind.dl_dest_addr_length); - } - if (daddrlen) { - *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length; - } - - if (grpaddr) { - *grpaddr = dlp -> unitdata_ind.dl_group_address; - } - - return data.len; -} - -/* - * expected - see if we got what we wanted. - */ -static int expected (prim, dlp, msgflags) - unsigned long prim; - union DL_primitives *dlp; - int msgflags; -{ - if (msgflags != RS_HIPRI) { - /* Message was not M_PCPROTO */ - return 0; - } - - if (dlp -> dl_primitive != prim) { - /* Incorrect/unexpected return message */ - return 0; - } - - return 1; -} - -/* - * strgetmsg - get a message from a stream, with timeout. - */ -static int strgetmsg (fd, ctlp, datap, flagsp, caller) - struct strbuf *ctlp, *datap; - char *caller; - int *flagsp; - int fd; -{ - int result; -#ifdef USE_POLL - struct pollfd pfd; - int count; - time_t now; - time_t starttime; - int to_msec; -#endif - -#ifdef USE_POLL - pfd.fd = fd; - pfd.events = POLLPRI; /* We're only interested in knowing - * when we can receive the next high - * priority message. - */ - pfd.revents = 0; - - now = time (&starttime); - while (now <= starttime + DLPI_MAXWAIT) { - to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000; - count = poll (&pfd, 1, to_msec); - - if (count == 0) { - /* log_fatal ("strgetmsg: timeout"); */ - return -1; - } else if (count < 0) { - if (errno == EAGAIN || errno == EINTR) { - time (&now); - continue; - } else { - /* log_fatal ("poll: %m"); */ - return -1; - } - } else { - break; - } - } -#else /* defined (USE_POLL) */ - /* - * Start timer. Can't use select, since it might return true if there - * were non High-Priority data available on the stream. - */ - (void) sigset (SIGALRM, sigalrm); - - if (alarm (DLPI_MAXWAIT) < 0) { - /* log_fatal ("alarm: %m"); */ - return -1; - } -#endif /* !defined (USE_POLL) */ - - /* - * Set flags argument and issue getmsg (). - */ - *flagsp = 0; - if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) { - return result; - } - -#ifndef USE_POLL - /* - * Stop timer. - */ - if (alarm (0) < 0) { - /* log_fatal ("alarm: %m"); */ - return -1; - } -#endif - - /* - * Check for MOREDATA and/or MORECTL. - */ - if (result & (MORECTL|MOREDATA)) { - return -1; - } - - /* - * Check for at least sizeof (long) control data portion. - */ - if (ctlp -> len < sizeof (long)) { - return -1; - } - - return 0; -} - -#ifndef USE_POLL -/* - * sigalrm - handle alarms. - */ -static void sigalrm (sig) - int sig; -{ - fprintf (stderr, "strgetmsg: timeout"); - exit (1); -} -#endif /* !defined (USE_POLL) */ - -int can_unicast_without_arp (ip) - struct interface_info *ip; -{ - return 1; -} - -int can_receive_unicast_unconfigured (ip) - struct interface_info *ip; -{ - return 1; -} - -int supports_multiple_interfaces (ip) - struct interface_info *ip; -{ - return 1; -} - -void maybe_setup_fallback () -{ - isc_result_t status; - struct interface_info *fbi = (struct interface_info *)0; - if (setup_fallback (&fbi, MDL)) { - if_register_fallback (fbi); - status = omapi_register_io_object ((omapi_object_t *)fbi, - if_readsocket, 0, - fallback_discard, 0, 0); - if (status != ISC_R_SUCCESS) - log_fatal ("Can't register I/O handle for %s: %s", - fbi -> name, isc_result_totext (status)); - interface_dereference (&fbi, MDL); - } -} -#endif /* USE_DLPI */ |