?? dlpi.c
字號:
/* $Header: /usr/cvsroot/target/src/wrn/wm/demo/lib/dlpi.c,v 1.2 2001/11/08 15:56:21 tneale Exp $ *//* * Copyright (C) 1999-2005 Wind River Systems, Inc. * All rights reserved. Provided under license only. * Distribution or other use of this software is only * permitted pursuant to the terms of a license agreement * from Wind River Systems (and is otherwise prohibited). * Refer to that license agreement for terms of use. *//**************************************************************************** * Copyright 1998 Integrated Systems, Inc. * All rights reserved. ****************************************************************************//* * $Log: dlpi.c,v $ * Revision 1.2 2001/11/08 15:56:21 tneale * Updated for newest file layout * * Revision 1.1.1.1 2001/11/05 17:48:41 tneale * Tornado shuffle * * Revision 2.3 2001/01/19 22:23:40 paul * Update copyright. * * Revision 2.2 2000/03/17 00:12:37 meister * Update copyright message * * Revision 2.1 1998/07/29 20:54:51 wes * First cut of the Solaris port. * (DLPI support, termios, minor tweaks to libraries and port header files) * * Revision 1.1.2.1 1998/07/24 21:45:41 wes * Initial implementation * *//* [clearcase]modification history-------------------01a,19apr05,job update copyright notices*//* * DLPI interface to ethernet for Attache testing under Solaris 2.x * * All access to DLPI should be through this module, the only thing we * expect our caller to do with our file descriptor is use it in * select() calls. There are enough name conflicts between the unix * networking code and the Attache networking code that it's probably * hopeless to have the two mingled in the same file. * * This was brutally converted from nit.c in a fit of madness. * * References: NIT manual pages * tcpdump source * CAP ethertalk source * netintro(4) manual page * NET-2 routed source * "How to use DLPI" document from Sun Internet Engineering, dated 30 Jun 1992 * DLPI specification. */#include <stdio.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <ctype.h>#include <fcntl.h>#include <sys/param.h>#include <sys/types.h>#include <sys/time.h>#include <sys/timeb.h>#include <sys/socket.h>#include <sys/file.h>#include <sys/ioctl.h>#include <stropts.h>#include <sys/dlpi.h>#include <sys/pfmod.h>#include <sys/sockio.h>#include <netinet/in.h>#include <net/if.h>#define __(x) x#include <wrn/wm/demo/dlpi.h>#ifdef __GNUC__#define alloca __builtin_alloca#endif#define MAXDLBUF 8192#define OFFADDR(s, n) (u_char*)((char*)(s) + (int)(n))/* * DLPI client stubs. */int dlreqspew (int fd, void *buf, size_t size){ struct strbuf ctl; ctl.maxlen = 0; ctl.len = size; ctl.buf = buf; return putmsg(fd, &ctl, NULL, 0);}int dlgetack (int fd, int exp_prim, int exp_flags, char *respbuf, int exp_size){ union DL_primitives *dlp; struct strbuf ctl; char tmpbuf[MAXDLBUF]; int flags = 0; if (!respbuf) respbuf = tmpbuf; /* XXX do a poll() here to wait for the response.. */ ctl.maxlen = exp_size; ctl.len = 0; ctl.buf = respbuf; if (getmsg(fd, &ctl, NULL, &flags) < 0) return -4; dlp = (union DL_primitives *)ctl.buf; if (dlp->dl_primitive != exp_prim) return -1; if (flags != exp_flags) return -2; if (ctl.len < exp_size) return -3; return 0;}int dlsar (int fd, void *reqbuf, size_t size, int exp_prim, int exp_flags, void *respbuf, int exp_size){ /* Flush the read queue, don't worry about it if we can't. */ (void) ioctl(fd, I_FLUSH, (char *) FLUSHR); if (dlreqspew(fd, reqbuf, size) < 0) return -1; return dlgetack(fd, exp_prim, exp_flags, respbuf, exp_size);}int dlattach(int fd, u_long ppa){ dl_attach_req_t attach_req; attach_req.dl_primitive = DL_ATTACH_REQ; attach_req.dl_ppa = ppa; return dlsar(fd, &attach_req, sizeof(attach_req), DL_OK_ACK, RS_HIPRI, NULL, sizeof(dl_ok_ack_t));}int dlbind(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest){ dl_bind_req_t bind_req; 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; return dlsar(fd, &bind_req, sizeof(bind_req), DL_BIND_ACK, RS_HIPRI, NULL, sizeof(dl_bind_ack_t));}int dlpromiscon(int fd, int level) { dl_promiscon_req_t promiscon_req; promiscon_req.dl_primitive = DL_PROMISCON_REQ; promiscon_req.dl_level = level; return dlsar (fd, &promiscon_req, sizeof(promiscon_req), DL_OK_ACK, RS_HIPRI, NULL, sizeof(dl_ok_ack_t));}int dlphysaddr(int fd, int which, char *phy, int len){ dl_phys_addr_req_t phys_addr_req; dl_phys_addr_ack_t phys_addr_ack; int tmp; union DL_primitives *dlp; phys_addr_req.dl_primitive = DL_PHYS_ADDR_REQ; phys_addr_req.dl_addr_type = which; tmp = dlsar (fd, &phys_addr_req, sizeof(phys_addr_req), DL_PHYS_ADDR_ACK, RS_HIPRI, &phys_addr_ack, sizeof(phys_addr_ack)); if (tmp < 0) return tmp; dlp=(union DL_primitives *)&phys_addr_ack; memcpy(phy, OFFADDR(dlp, dlp->physaddr_ack.dl_addr_offset), len); return 0; }/* * Open a STREAMS driver for the interface and attach it to the interface named 'device'. * Returns DLPI file descriptor, or -1 if an error occurs. * * Since this implementation uses the same ethernet address as the host * on which it's running, fill in Attache's idea of the MAC address. * * N.B. the order of calls of the STREAMS primitives here is * evidently fairly subtle and is not covered by existing documentation. * * Looking at known working code (e.g., LBL libpcap) finally allowed * me to get things to work right; based on reading that other code, * it appears that this will require some work on systems other than * Solaris. */int dlpi_open(char *ifname, unsigned mtu, unsigned char *mac){ struct strioctl sioc; char driver[16]; int fd; u_long unit; char *cp; /* * parse the unit number out of the ifname.. */ sprintf(driver, "/dev/%s", ifname); cp = &driver[strlen(driver)]; while(isdigit((int)cp[-1])) /* XXX int cast to quiet gcc */ --cp; unit = atoi(cp); *cp = '\0'; /* * Look for cloned link-layer driver.. */ if ((fd = open(driver, O_RDWR)) < 0) { perror("couldn't clone DLPI device"); return -1; } if (dlattach(fd, unit) < 0) { perror("couldn't attach dlpi unit\n"); return -1; } /* * Enable discrete messages. */ if (ioctl(fd, I_SRDOPT, (char *) RMSGD) < 0) { perror("couldn't enable discrete DLPI messages"); return -1; } /* * Don't bother with buffering, or truncation for now. */ /* * Put the interface into promiscuous mode so that we'll see packets * to our faked MAC address.. */ if (dlpromiscon(fd, DL_PROMISC_PHYS) < 0) { perror("dlpi: failed to set promisc PHYS mode\n"); } /* * Get all SAP's (this apparently needs to happen *after* setting * the lower-level promiscuous mode */ if (dlpromiscon(fd, DL_PROMISC_SAP) < 0) perror("dlpi: failed to set promisc SAP mode"); /* * We bind last since comments in libpcap suggest that this is most portable. */ if (dlbind(fd, 0, 0, DL_CLDLS, 0, 0) < 0) { perror("couldn't dlbind\n"); } /* Set raw mode. if this fails, we *should* blow up since the protocol's different.. */ sioc.ic_cmd = DLIOCRAW; sioc.ic_timout = -1; sioc.ic_len = 0; sioc.ic_dp = 0; if (ioctl(fd, I_STR, &sioc) < 0) { perror("couldn't set RAW mode, continuing..\n"); } /* * Push packet filter module. */ if (ioctl(fd, I_PUSH, "pfmod") < 0) { perror("couldn't push packet filter STREAMS module, continuing.."); } else { struct packetfilt pfil; u_short *pfp = &pfil.Pf_Filter[0]; /* * Yum. Interpreted LIW code, the result of several hours of mental pain. * This *might* be an optimal instruction schedule. * * Whoever named the ENF_C{N,}{AND,OR} ops was.. confused... * But, well... */ *pfp++ = ENF_PUSHLIT; *pfp++ = 0x0100; /* multicast bit */ *pfp++ = (ENF_PUSHWORD+0) | ENF_AND; /* mask with first word of mac */ *pfp++ = ENF_PUSHZERO | ENF_CNAND; /* succeed if nonzero */ *pfp++ = ENF_PUSHLIT; *pfp++ = ntohs(*(u_short *)mac); /* first word of mac */ *pfp++ = (ENF_PUSHWORD+0) | ENF_CAND; /* fail if not equal */ *pfp++ = ENF_PUSHLIT; *pfp++ = ntohs(*(u_short *)(mac+2)); /* second word of mac */ *pfp++ = (ENF_PUSHWORD+1) | ENF_CAND; /* fail if not equal */ *pfp++ = ENF_PUSHLIT; *pfp++ = ntohs(*(u_short *)(mac+4)); /* third word of mac */ *pfp++ = (ENF_PUSHWORD+2) | ENF_EQ; /* succeed if equal.. */ pfil.Pf_Priority = 0; pfil.Pf_FilterLen = pfp - &pfil.Pf_Filter[0]; sioc.ic_cmd = PFIOCSETF; sioc.ic_timout = -1; sioc.ic_len = sizeof(pfil); sioc.ic_dp = (void *)&pfil; if (ioctl(fd, I_STR, &sioc) < 0) { perror("couldn't set packet filter, continuing.."); } } /* As last action, flush the read queue.. */ (void) ioctl(fd, I_FLUSH, (char *) FLUSHR); return fd;}/* * Read a DLPI buffer and hand its contents off to Attache as packets. * This is based on the readloop() function in tcpdump's BPF code and * on the dlpi(4) manual page. * * The handler routine supplied by the Attache-side code gets three * arguments: a pointer to the packet data, the length of the packet * data, and the length that the real packet was on the wire. * * There's probably nothing useful that Attache can do with a truncated * packet, but the info is there, so we may as well pass it along. */int dlpi_read (int fd, unsigned mtu, void (*handler)(unsigned char *, unsigned, unsigned, void *), void *cookie){ unsigned char *buf; int i, flags; struct strbuf data; if ((buf = (unsigned char *) alloca(mtu)) == 0) { fprintf(stderr, "alloca(%d) failed\n", mtu); return -1; } data.buf = buf; data.maxlen = mtu; data.len = 0; /* * Try to read a packet, restart if we get screwed by the debugger. * Return on other error or on EOF. */ flags = 0; do { i = getmsg(fd, NULL, &data, &flags); } while (i < 0 && errno == EINTR); if (i>=0) i=data.len; if (i <= 0) return i; /* * In theory, since we've got the stream in discrete message mode, * we can just assume that we got one packet. */ handler(buf, i, i, cookie); return 1;}/* * Write a packet to the DLPI stream. */int dlpi_write(int fd, unsigned char *data, unsigned datalen){ struct strbuf dbuf; dbuf.buf = data; dbuf.len = datalen; dbuf.maxlen = 0; return putmsg(fd, 0, &dbuf, 0) < 0 ? -1 : datalen;}/* * Close a DLPI interface. */void dlpi_close(int fd){ (void) close(fd);}#if defined(SIOCGIFCONF)/* * Find all ethernet interfaces. This is a simplified version of the * code that works on NetBSD, I dunno yet whether this will work on SunOS. */void dlpi_find(void (*handler)(char *, void *), void *cookie){ char buffer[5000]; struct ifconf ifc; struct ifreq *ifr; int s; if (!handler) return; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return; } /* shut up purify whining about uninit memory.. */ memset(buffer, 0, sizeof(buffer)); ifc.ifc_len = sizeof(buffer); ifc.ifc_buf = buffer; if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) { perror("ioctl"); (void) close(s); return; } for (ifr = ifc.ifc_req; ((char *) ifr) < ifc.ifc_buf + ifc.ifc_len; ++ifr) { handler(ifr->ifr_name, cookie); } (void) close(s);}#endif /* defined(SIOCGIFCONF) */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -