static int pcap_activate_dlpi(pcap_t *p) { #ifdef DL_HP_RAWDLS struct pcap_dlpi *pd = p->priv; #endif int status = 0; int retv; register char *cp; int ppa; #ifdef HAVE_SOLARIS int isatm = 0; #endif register dl_info_ack_t *infop; #ifdef HAVE_SYS_BUFMOD_H bpf_u_int32 ss; #ifdef HAVE_SOLARIS register char *release; bpf_u_int32 osmajor, osminor, osmicro; #endif #endif bpf_u_int32 buf[MAXDLBUF]; char dname[100]; #ifndef HAVE_DEV_DLPI char dname2[100]; #endif #ifdef HAVE_DEV_DLPI /* ** Remove any "/dev/" on the front of the device. */ cp = strrchr(p->opt.source, '/'); if (cp == NULL) strlcpy(dname, p->opt.source, sizeof(dname)); else strlcpy(dname, cp + 1, sizeof(dname)); /* * Split the device name into a device type name and a unit number; * chop off the unit number, so "dname" is just a device type name. */ cp = split_dname(dname, &ppa, p->errbuf); if (cp == NULL) { status = PCAP_ERROR_NO_SUCH_DEVICE; goto bad; } *cp = '\0'; /* * Use "/dev/dlpi" as the device. * * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that * the "dl_mjr_num" field is for the "major number of interface * driver"; that's the major of "/dev/dlpi" on the system on * which I tried this, but there may be DLPI devices that * use a different driver, in which case we may need to * search "/dev" for the appropriate device with that major * device number, rather than hardwiring "/dev/dlpi". */ cp = "/dev/dlpi"; if ((p->fd = open(cp, O_RDWR)) < 0) { if (errno == EPERM || errno == EACCES) status = PCAP_ERROR_PERM_DENIED; else status = PCAP_ERROR; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", cp, pcap_strerror(errno)); goto bad; } #ifdef DL_HP_RAWDLS /* * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and * receiving packets on the same descriptor - you need separate * descriptors for sending and receiving, bound to different SAPs. * * If the open fails, we just leave -1 in "pd->send_fd" and reject * attempts to send packets, just as if, in pcap-bpf.c, we fail * to open the BPF device for reading and writing, we just try * to open it for reading only and, if that succeeds, just let * the send attempts fail. */ pd->send_fd = open(cp, O_RDWR); #endif /* * Get a table of all PPAs for that device, and search that * table for the specified device type name and unit number. */ ppa = get_dlpi_ppa(p->fd, dname, ppa, p->errbuf); if (ppa < 0) { status = ppa; goto bad; } #else /* * If the device name begins with "/", assume it begins with * the pathname of the directory containing the device to open; * otherwise, concatenate the device directory name and the * device name. */ if (*p->opt.source == '/') strlcpy(dname, p->opt.source, sizeof(dname)); else snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, p->opt.source); /* * Get the unit number, and a pointer to the end of the device * type name. */ cp = split_dname(dname, &ppa, p->errbuf); if (cp == NULL) { status = PCAP_ERROR_NO_SUCH_DEVICE; goto bad; } /* * Make a copy of the device pathname, and then remove the unit * number from the device pathname. */ strlcpy(dname2, dname, sizeof(dname)); *cp = '\0'; /* Try device without unit number */ if ((p->fd = open(dname, O_RDWR)) < 0) { if (errno != ENOENT) { if (errno == EPERM || errno == EACCES) status = PCAP_ERROR_PERM_DENIED; else status = PCAP_ERROR; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dname, pcap_strerror(errno)); goto bad; } /* Try again with unit number */ if ((p->fd = open(dname2, O_RDWR)) < 0) { if (errno == ENOENT) { status = PCAP_ERROR_NO_SUCH_DEVICE; /* * We provide an error message even * for this error, for diagnostic * purposes (so that, for example, * the app can show the message if the * user requests it). * * In it, we just report "No DLPI device * found" with the device name, so people * don't get confused and think, for example, * that if they can't capture on "lo0" * on Solaris the fix is to change libpcap * (or the application that uses it) to * look for something other than "/dev/lo0", * as the fix is to look for an operating * system other than Solaris - you just * *can't* capture on a loopback interface * on Solaris, the lack of a DLPI device * for the loopback interface is just a * symptom of that inability. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: No DLPI device found", p->opt.source); } else { if (errno == EPERM || errno == EACCES) status = PCAP_ERROR_PERM_DENIED; else status = PCAP_ERROR; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2, pcap_strerror(errno)); } goto bad; } /* XXX Assume unit zero */ ppa = 0; } #endif /* ** Attach if "style 2" provider */ if (dlinforeq(p->fd, p->errbuf) < 0 || dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) { status = PCAP_ERROR; goto bad; } infop = &(MAKE_DL_PRIMITIVES(buf))->info_ack; #ifdef HAVE_SOLARIS if (infop->dl_mac_type == DL_IPATM) isatm = 1; #endif if (infop->dl_provider_style == DL_STYLE2) { retv = dl_doattach(p->fd, ppa, p->errbuf); if (retv < 0) { status = retv; goto bad; } #ifdef DL_HP_RAWDLS if (pd->send_fd >= 0) { retv = dl_doattach(pd->send_fd, ppa, p->errbuf); if (retv < 0) { status = retv; goto bad; } } #endif } if (p->opt.rfmon) { /* * This device exists, but we don't support monitor mode * any platforms that support DLPI. */ status = PCAP_ERROR_RFMON_NOTSUP; goto bad; } #ifdef HAVE_DLPI_PASSIVE /* * Enable Passive mode to be able to capture on aggregated link. * Not supported in all Solaris versions. */ dlpassive(p->fd, p->errbuf); #endif /* ** Bind (defer if using HP-UX 9 or HP-UX 10.20 or later, totally ** skip if using SINIX) */ #if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20_OR_LATER) && !defined(sinix) #ifdef _AIX /* ** AIX. ** According to IBM's AIX Support Line, the dl_sap value ** should not be less than 0x600 (1536) for standard Ethernet. ** However, we seem to get DL_BADADDR - "DLSAP addr in improper ** format or invalid" - errors if we use 1537 on the "tr0" ** device, which, given that its name starts with "tr" and that ** it's IBM, probably means a Token Ring device. (Perhaps we ** need to use 1537 on "/dev/dlpi/en" because that device is for ** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and ** it rejects invalid Ethernet types.) ** ** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea ** says that works on Token Ring (he says that 0 does *not* ** work; perhaps that's considered an invalid LLC SAP value - I ** assume the SAP value in a DLPI bind is an LLC SAP for network ** types that use 802.2 LLC). */ if ((dlbindreq(p->fd, 1537, p->errbuf) < 0 && dlbindreq(p->fd, 2, p->errbuf) < 0) || dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) { status = PCAP_ERROR; goto bad; } #elif defined(DL_HP_RAWDLS) /* ** HP-UX 10.0x and 10.1x. */ if (dl_dohpuxbind(p->fd, p->errbuf) < 0) { status = PCAP_ERROR; goto bad; } if (pd->send_fd >= 0) { /* ** XXX - if this fails, just close send_fd and ** set it to -1, so that you can't send but can ** still receive? */ if (dl_dohpuxbind(pd->send_fd, p->errbuf) < 0) { status = PCAP_ERROR; goto bad; } } #else /* neither AIX nor HP-UX */ /* ** Not Sinix, and neither AIX nor HP-UX - Solaris, and any other ** OS using DLPI. **/ if (dlbindreq(p->fd, 0, p->errbuf) < 0 || dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) { status = PCAP_ERROR; goto bad; } #endif /* AIX vs. HP-UX vs. other */ #endif /* !HP-UX 9 and !HP-UX 10.20 or later and !SINIX */ #ifdef HAVE_SOLARIS if (isatm) { /* ** Have to turn on some special ATM promiscuous mode ** for SunATM. ** Do *NOT* turn regular promiscuous mode on; it doesn't ** help, and may break things. */ if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) { status = PCAP_ERROR; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "A_PROMISCON_REQ: %s", pcap_strerror(errno)); goto bad; } } else #endif if (p->opt.promisc) { /* ** Enable promiscuous (not necessary on send FD) */ retv = dlpromiscon(p, DL_PROMISC_PHYS); if (retv < 0) { if (retv == PCAP_ERROR_PERM_DENIED) status = PCAP_ERROR_PROMISC_PERM_DENIED; else status = retv; goto bad; } /* ** Try to enable multicast (you would have thought ** promiscuous would be sufficient). (Skip if using ** HP-UX or SINIX) (Not necessary on send FD) */ #if !defined(__hpux) && !defined(sinix) retv = dlpromiscon(p, DL_PROMISC_MULTI); if (retv < 0) status = PCAP_WARNING; #endif } /* ** Try to enable SAP promiscuity (when not in promiscuous mode ** when using HP-UX, when not doing SunATM on Solaris, and never ** under SINIX) (Not necessary on send FD) */ #ifndef sinix #if defined(__hpux) /* HP-UX - only do this when not in promiscuous mode */ if (!p->opt.promisc) { #elif defined(HAVE_SOLARIS) /* Solaris - don't do this on SunATM devices */ if (!isatm) { #else /* Everything else (except for SINIX) - always do this */ { #endif retv = dlpromiscon(p, DL_PROMISC_SAP); if (retv < 0) { if (p->opt.promisc) { /* * Not fatal, since the DL_PROMISC_PHYS mode * worked. * * Report it as a warning, however. */ status = PCAP_WARNING; } else { /* * Fatal. */ status = retv; goto bad; } } } #endif /* sinix */ /* ** HP-UX 9, and HP-UX 10.20 or later, must bind after setting ** promiscuous options. */ #if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20_OR_LATER) if (dl_dohpuxbind(p->fd, p->errbuf) < 0) { status = PCAP_ERROR; goto bad; } /* ** We don't set promiscuous mode on the send FD, but we'll defer ** binding it anyway, just to keep the HP-UX 9/10.20 or later ** code together. */ if (pd->send_fd >= 0) { /* ** XXX - if this fails, just close send_fd and ** set it to -1, so that you can't send but can ** still receive? */ if (dl_dohpuxbind(pd->send_fd, p->errbuf) < 0) { status = PCAP_ERROR; goto bad; } } #endif /* ** Determine link type ** XXX - get SAP length and address length as well, for use ** when sending packets. */ if (dlinforeq(p->fd, p->errbuf) < 0 || dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) { status = PCAP_ERROR; goto bad; } infop = &(MAKE_DL_PRIMITIVES(buf))->info_ack; if (pcap_process_mactype(p, infop->dl_mac_type) != 0) { status = PCAP_ERROR; goto bad; } #ifdef DLIOCRAW /* ** This is a non standard SunOS hack to get the full raw link-layer ** header. */ if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { status = PCAP_ERROR; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s", pcap_strerror(errno)); goto bad; } #endif #ifdef HAVE_SYS_BUFMOD_H ss = p->snapshot; /* ** There is a bug in bufmod(7). When dealing with messages of ** less than snaplen size it strips data from the beginning not ** the end. ** ** This bug is fixed in 5.3.2. Also, there is a patch available. ** Ask for bugid 1149065. */ #ifdef HAVE_SOLARIS release = get_release(&osmajor, &osminor, &osmicro); if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && getenv("BUFMOD_FIXED") == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.", release); ss = 0; status = PCAP_WARNING; } #endif /* Push and configure bufmod. */ if (pcap_conf_bufmod(p, ss) != 0) { status = PCAP_ERROR; goto bad; } #endif /* ** As the last operation flush the read side. */ if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { status = PCAP_ERROR; snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", pcap_strerror(errno)); goto bad; } /* Allocate data buffer. */ if (pcap_alloc_databuf(p) != 0) { status = PCAP_ERROR; goto bad; } /* * Success. * * "p->fd" is an FD for a STREAMS device, so "select()" and * "poll()" should work on it. */ p->selectable_fd = p->fd; p->read_op = pcap_read_dlpi; p->inject_op = pcap_inject_dlpi; p->setfilter_op = install_bpf_program; /* no kernel filtering */ p->setdirection_op = NULL; /* Not implemented.*/ p->set_datalink_op = NULL; /* can't change data link type */ p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_stats_dlpi; p->cleanup_op = pcap_cleanup_dlpi; return (status); bad: pcap_cleanup_dlpi(p); return (status); } /* * Split a device name into a device type name and a unit number; * return the a pointer to the beginning of the unit number, which * is the end of the device type name, and set "*unitp" to the unit * number. * * Returns NULL on error, and fills "ebuf" with an error message. */ static char * split_dname(char *device, int *unitp, char *ebuf) { char *cp; char *eos; long unit; /* * Look for a number at the end of the device name string. */ cp = device + strlen(device) - 1; if (*cp < '0' || *cp > '9') { snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number", device); return (NULL); } /* Digits at end of string are unit number */ while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9') cp--; errno = 0; unit = strtol(cp, &eos, 10); if (*eos != '\0') { snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device); return (NULL); } if (errno == ERANGE || unit > INT_MAX) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large", device); return (NULL); } if (unit < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative", device); return (NULL); } *unitp = (int)unit; return (cp); } static int dl_doattach(int fd, int ppa, char *ebuf) { dl_attach_req_t req; bpf_u_int32 buf[MAXDLBUF]; int err; req.dl_primitive = DL_ATTACH_REQ; req.dl_ppa = ppa; if (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf) < 0) return (PCAP_ERROR); err = dlokack(fd, "attach", (char *)buf, ebuf); if (err < 0) return (err); return (0); }
pcap_t * pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf) { register char *cp; register pcap_t *p; int ppa; #ifdef HAVE_SOLARIS int isatm = 0; #endif register dl_info_ack_t *infop; #ifdef HAVE_SYS_BUFMOD_H bpf_u_int32 ss, chunksize; #ifdef HAVE_SOLARIS register char *release; bpf_u_int32 osmajor, osminor, osmicro; #endif #endif bpf_u_int32 buf[MAXDLBUF]; char dname[100]; #ifndef HAVE_DEV_DLPI char dname2[100]; #endif p = (pcap_t *)malloc(sizeof(*p)); if (p == NULL) { strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); return (NULL); } memset(p, 0, sizeof(*p)); p->fd = -1; /* indicate that it hasn't been opened yet */ p->send_fd = -1; #ifdef HAVE_DEV_DLPI /* ** Remove any "/dev/" on the front of the device. */ cp = strrchr(device, '/'); if (cp == NULL) strlcpy(dname, device, sizeof(dname)); else strlcpy(dname, cp + 1, sizeof(dname)); /* * Split the device name into a device type name and a unit number; * chop off the unit number, so "dname" is just a device type name. */ cp = split_dname(dname, &ppa, ebuf); if (cp == NULL) goto bad; *cp = '\0'; /* * Use "/dev/dlpi" as the device. * * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that * the "dl_mjr_num" field is for the "major number of interface * driver"; that's the major of "/dev/dlpi" on the system on * which I tried this, but there may be DLPI devices that * use a different driver, in which case we may need to * search "/dev" for the appropriate device with that major * device number, rather than hardwiring "/dev/dlpi". */ cp = "/dev/dlpi"; if ((p->fd = open(cp, O_RDWR)) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", cp, pcap_strerror(errno)); goto bad; } #ifdef DL_HP_RAWDLS /* * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and * receiving packets on the same descriptor - you need separate * descriptors for sending and receiving, bound to different SAPs. * * If the open fails, we just leave -1 in "p->send_fd" and reject * attempts to send packets, just as if, in pcap-bpf.c, we fail * to open the BPF device for reading and writing, we just try * to open it for reading only and, if that succeeds, just let * the send attempts fail. */ p->send_fd = open(cp, O_RDWR); #endif /* * Get a table of all PPAs for that device, and search that * table for the specified device type name and unit number. */ ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf); if (ppa < 0) goto bad; #else /* * If the device name begins with "/", assume it begins with * the pathname of the directory containing the device to open; * otherwise, concatenate the device directory name and the * device name. */ if (*device == '/') strlcpy(dname, device, sizeof(dname)); else snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, device); /* * Get the unit number, and a pointer to the end of the device * type name. */ cp = split_dname(dname, &ppa, ebuf); if (cp == NULL) goto bad; /* * Make a copy of the device pathname, and then remove the unit * number from the device pathname. */ strlcpy(dname2, dname, sizeof(dname)); *cp = '\0'; /* Try device without unit number */ if ((p->fd = open(dname, O_RDWR)) < 0) { if (errno != ENOENT) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname, pcap_strerror(errno)); goto bad; } /* Try again with unit number */ if ((p->fd = open(dname2, O_RDWR)) < 0) { if (errno == ENOENT) { /* * We just report "No DLPI device found" * with the device name, so people don't * get confused and think, for example, * that if they can't capture on "lo0" * on Solaris the fix is to change libpcap * (or the application that uses it) to * look for something other than "/dev/lo0", * as the fix is to look for an operating * system other than Solaris - you just * *can't* capture on a loopback interface * on Solaris, the lack of a DLPI device * for the loopback interface is just a * symptom of that inability. */ snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: No DLPI device found", device); } else { snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname2, pcap_strerror(errno)); } goto bad; } /* XXX Assume unit zero */ ppa = 0; } #endif p->snapshot = snaplen; /* ** Attach if "style 2" provider */ if (dlinforeq(p->fd, ebuf) < 0 || dlinfoack(p->fd, (char *)buf, ebuf) < 0) goto bad; infop = &((union DL_primitives *)buf)->info_ack; #ifdef HAVE_SOLARIS if (infop->dl_mac_type == DL_IPATM) isatm = 1; #endif if (infop->dl_provider_style == DL_STYLE2) { if (dl_doattach(p->fd, ppa, ebuf) < 0) goto bad; #ifdef DL_HP_RAWDLS if (p->send_fd >= 0) { if (dl_doattach(p->send_fd, ppa, ebuf) < 0) goto bad; } #endif } /* ** Bind (defer if using HP-UX 9 or HP-UX 10.20 or later, totally ** skip if using SINIX) */ #if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20_OR_LATER) && !defined(sinix) #ifdef _AIX /* ** AIX. ** According to IBM's AIX Support Line, the dl_sap value ** should not be less than 0x600 (1536) for standard Ethernet. ** However, we seem to get DL_BADADDR - "DLSAP addr in improper ** format or invalid" - errors if we use 1537 on the "tr0" ** device, which, given that its name starts with "tr" and that ** it's IBM, probably means a Token Ring device. (Perhaps we ** need to use 1537 on "/dev/dlpi/en" because that device is for ** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and ** it rejects invalid Ethernet types.) ** ** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea ** says that works on Token Ring (he says that 0 does *not* ** work; perhaps that's considered an invalid LLC SAP value - I ** assume the SAP value in a DLPI bind is an LLC SAP for network ** types that use 802.2 LLC). */ if ((dlbindreq(p->fd, 1537, ebuf) < 0 && dlbindreq(p->fd, 2, ebuf) < 0) || dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0) goto bad; #elif defined(DL_HP_RAWDLS) /* ** HP-UX 10.0x and 10.1x. */ if (dl_dohpuxbind(p->fd, ebuf) < 0) goto bad; if (p->send_fd >= 0) { /* ** XXX - if this fails, just close send_fd and ** set it to -1, so that you can't send but can ** still receive? */ if (dl_dohpuxbind(p->send_fd, ebuf) < 0) goto bad; } #else /* neither AIX nor HP-UX */ /* ** Not Sinix, and neither AIX nor HP-UX - Solaris, and any other ** OS using DLPI. **/ if (dlbindreq(p->fd, 0, ebuf) < 0 || dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0) goto bad; #endif /* AIX vs. HP-UX vs. other */ #endif /* !HP-UX 9 and !HP-UX 10.20 or later and !SINIX */ #ifdef HAVE_SOLARIS if (isatm) { /* ** Have to turn on some special ATM promiscuous mode ** for SunATM. ** Do *NOT* turn regular promiscuous mode on; it doesn't ** help, and may break things. */ if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "A_PROMISCON_REQ: %s", pcap_strerror(errno)); goto bad; } } else #endif if (promisc) { /* ** Enable promiscuous (not necessary on send FD) */ if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 || dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0) goto bad; /* ** Try to enable multicast (you would have thought ** promiscuous would be sufficient). (Skip if using ** HP-UX or SINIX) (Not necessary on send FD) */ #if !defined(__hpux) && !defined(sinix) if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 || dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0) fprintf(stderr, "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf); #endif } /* ** Try to enable SAP promiscuity (when not in promiscuous mode ** when using HP-UX, when not doing SunATM on Solaris, and never ** under SINIX) (Not necessary on send FD) */ #ifndef sinix if ( #ifdef __hpux !promisc && #endif #ifdef HAVE_SOLARIS !isatm && #endif (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 || dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) { /* Not fatal if promisc since the DL_PROMISC_PHYS worked */ if (promisc) fprintf(stderr, "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf); else goto bad; } #endif /* sinix */ /* ** HP-UX 9, and HP-UX 10.20 or later, must bind after setting ** promiscuous options. */ #if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20_OR_LATER) if (dl_dohpuxbind(p->fd, ebuf) < 0) goto bad; /* ** We don't set promiscuous mode on the send FD, but we'll defer ** binding it anyway, just to keep the HP-UX 9/10.20 or later ** code together. */ if (p->send_fd >= 0) { /* ** XXX - if this fails, just close send_fd and ** set it to -1, so that you can't send but can ** still receive? */ if (dl_dohpuxbind(p->send_fd, ebuf) < 0) goto bad; } #endif /* ** Determine link type ** XXX - get SAP length and address length as well, for use ** when sending packets. */ if (dlinforeq(p->fd, ebuf) < 0 || dlinfoack(p->fd, (char *)buf, ebuf) < 0) goto bad; infop = &((union DL_primitives *)buf)->info_ack; switch (infop->dl_mac_type) { case DL_CSMACD: case DL_ETHER: p->linktype = DLT_EN10MB; p->offset = 2; /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). */ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); /* * If that fails, just leave the list empty. */ if (p->dlt_list != NULL) { p->dlt_list[0] = DLT_EN10MB; p->dlt_list[1] = DLT_DOCSIS; p->dlt_count = 2; } break; case DL_FDDI: p->linktype = DLT_FDDI; p->offset = 3; break; case DL_TPR: /* * XXX - what about DL_TPB? Is that Token Bus? */ p->linktype = DLT_IEEE802; p->offset = 2; break; #ifdef HAVE_SOLARIS case DL_IPATM: p->linktype = DLT_SUNATM; p->offset = 0; /* works for LANE and LLC encapsulation */ break; #endif default: snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu", (unsigned long)infop->dl_mac_type); goto bad; } #ifdef DLIOCRAW /* ** This is a non standard SunOS hack to get the full raw link-layer ** header. */ if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s", pcap_strerror(errno)); goto bad; } #endif #ifdef HAVE_SYS_BUFMOD_H /* ** Another non standard call to get the data nicely buffered */ if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s", pcap_strerror(errno)); goto bad; } /* ** Now that the bufmod is pushed lets configure it. ** ** There is a bug in bufmod(7). When dealing with messages of ** less than snaplen size it strips data from the beginning not ** the end. ** ** This bug is supposed to be fixed in 5.3.2. Also, there is a ** patch available. Ask for bugid 1149065. */ ss = snaplen; #ifdef HAVE_SOLARIS release = get_release(&osmajor, &osminor, &osmicro); if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && getenv("BUFMOD_FIXED") == NULL) { fprintf(stderr, "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.\n", release); ss = 0; } #endif if (ss > 0 && strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s", pcap_strerror(errno)); goto bad; } /* ** Set up the bufmod timeout */ if (to_ms != 0) { struct timeval to; to.tv_sec = to_ms / 1000; to.tv_usec = (to_ms * 1000) % 1000000; if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s", pcap_strerror(errno)); goto bad; } } /* ** Set the chunk length. */ chunksize = CHUNKSIZE; if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) != 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSCHUNKP: %s", pcap_strerror(errno)); goto bad; } #endif /* ** As the last operation flush the read side. */ if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", pcap_strerror(errno)); goto bad; } /* Allocate data buffer */ p->bufsize = PKTBUFSIZE; p->buffer = (u_char *)malloc(p->bufsize + p->offset); if (p->buffer == NULL) { strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); goto bad; } /* * "p->fd" is an FD for a STREAMS device, so "select()" and * "poll()" should work on it. */ p->selectable_fd = p->fd; p->read_op = pcap_read_dlpi; p->inject_op = pcap_inject_dlpi; p->setfilter_op = install_bpf_program; /* no kernel filtering */ p->setdirection_op = NULL; /* Not implemented.*/ p->set_datalink_op = NULL; /* can't change data link type */ p->getnonblock_op = pcap_getnonblock_fd; p->setnonblock_op = pcap_setnonblock_fd; p->stats_op = pcap_stats_dlpi; p->close_op = pcap_close_dlpi; return (p); bad: if (p->fd >= 0) close(p->fd); if (p->send_fd >= 0) close(p->send_fd); /* * Get rid of any link-layer type list we allocated. */ if (p->dlt_list != NULL) free(p->dlt_list); free(p); return (NULL); }