⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dlpi.c

📁 DHCP服务器源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 lintstatic 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))# endifstatic 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_POLLstatic void	sigalrm PROTO ((int sig));# endifstatic 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_SENDvoid if_reinitialize_send (info)	struct interface_info *info;{}#endif#ifdef USE_DLPI_RECEIVEvoid 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 intstrioctl (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_SENDvoid 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;        /*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -