/* * sppp_dl_promiscon() * * MT-Perimeters: * exclusive inner, shared outer. * * Description: * Called by qwriter (INNER) from sppp_dlpromisconreq as the result of * receiving a DL_PROMISCON_REQ message. */ static void sppp_dl_promiscon(queue_t *q, mblk_t *mp) { spppstr_t *sps; sppa_t *ppa; ASSERT(q != NULL && q->q_ptr != NULL); sps = (spppstr_t *)q->q_ptr; ASSERT(!IS_SPS_PROMISC(sps)); ASSERT(mp != NULL && mp->b_rptr != NULL); ppa = sps->sps_ppa; sps->sps_flags |= SPS_PROMISC; /* * We can't be sure that the sps_ppa field is valid, since the DLPI * spec says that DL_PROMISCON_REQ can be issued at any state, i.e., * the request can be issued even before DL_ATTACH_REQ or PPPIO_ATTACH * be issued to associate this stream with a ppa. */ if (ppa != NULL) { rw_enter(&ppa->ppa_sib_lock, RW_WRITER); ppa->ppa_promicnt++; rw_exit(&ppa->ppa_sib_lock); } DBGDLPI((CE_CONT, "/%d: promiscuous mode on\n", sps->sps_mn_id)); dlokack(q, mp, DL_PROMISCON_REQ); }
/* * DL_DETACH_REQ */ static void proto_detach_req(dld_str_t *dsp, mblk_t *mp) { queue_t *q = dsp->ds_wq; t_uscalar_t dl_err; if (MBLKL(mp) < sizeof (dl_detach_req_t)) { dl_err = DL_BADPRIM; goto failed; } if (dsp->ds_dlstate != DL_UNBOUND) { dl_err = DL_OUTSTATE; goto failed; } if (dsp->ds_style == DL_STYLE1) { dl_err = DL_BADPRIM; goto failed; } ASSERT(dsp->ds_datathr_cnt == 0); dsp->ds_dlstate = DL_DETACH_PENDING; dld_str_detach(dsp); dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); return; failed: dlerrorack(q, mp, DL_DETACH_REQ, dl_err, 0); }
/* * DL_UNBIND_REQ */ static void proto_unbind_req(dld_str_t *dsp, mblk_t *mp) { queue_t *q = dsp->ds_wq; t_uscalar_t dl_err; mac_perim_handle_t mph; if (MBLKL(mp) < sizeof (dl_unbind_req_t)) { dl_err = DL_BADPRIM; goto failed; } if (dsp->ds_dlstate != DL_IDLE) { dl_err = DL_OUTSTATE; goto failed; } mutex_enter(&dsp->ds_lock); while (dsp->ds_datathr_cnt != 0) cv_wait(&dsp->ds_datathr_cv, &dsp->ds_lock); dsp->ds_dlstate = DL_UNBIND_PENDING; mutex_exit(&dsp->ds_lock); mac_perim_enter_by_mh(dsp->ds_mh, &mph); /* * Unbind the channel to stop packets being received. */ dls_unbind(dsp); /* * Disable polling mode, if it is enabled. */ (void) dld_capab_poll_disable(dsp, NULL); /* * Clear LSO flags. */ dsp->ds_lso = B_FALSE; dsp->ds_lso_max = 0; /* * Clear the receive callback. */ dls_rx_set(dsp, NULL, NULL); dsp->ds_direct = B_FALSE; /* * Set the mode back to the default (unitdata). */ dsp->ds_mode = DLD_UNITDATA; dsp->ds_dlstate = DL_UNBOUND; dls_active_clear(dsp, B_FALSE); mac_perim_exit(mph); dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ); return; failed: dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0); }
/* * DL_UDQOS_REQ */ static void proto_udqos_req(dld_str_t *dsp, mblk_t *mp) { dl_udqos_req_t *dlp = (dl_udqos_req_t *)mp->b_rptr; dl_qos_cl_sel1_t *selp; int off, len; t_uscalar_t dl_err; queue_t *q = dsp->ds_wq; off = dlp->dl_qos_offset; len = dlp->dl_qos_length; if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) { dl_err = DL_BADPRIM; goto failed; } selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off); if (selp->dl_qos_type != DL_QOS_CL_SEL1) { dl_err = DL_BADQOSTYPE; goto failed; } if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 || selp->dl_priority < 0) { dl_err = DL_BADQOSPARAM; goto failed; } dsp->ds_pri = selp->dl_priority; dlokack(q, mp, DL_UDQOS_REQ); return; failed: dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0); }
/* * DL_PASSIVE_REQ */ static void proto_passive_req(dld_str_t *dsp, mblk_t *mp) { t_uscalar_t dl_err; /* * If we've already become active by issuing an active primitive, * then it's too late to try to become passive. */ if (dsp->ds_passivestate == DLD_ACTIVE) { dl_err = DL_OUTSTATE; goto failed; } if (MBLKL(mp) < sizeof (dl_passive_req_t)) { dl_err = DL_BADPRIM; goto failed; } dsp->ds_passivestate = DLD_PASSIVE; dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ); return; failed: dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, dl_err, 0); }
/* * sppp_dl_promiscoff() * * MT-Perimeters: * exclusive inner, shared outer. * * Description: * Called by qwriter (INNER) from sppp_dlpromiscoffreq as the result of * receiving a DL_PROMISCOFF_REQ message. */ static void sppp_dl_promiscoff(queue_t *q, mblk_t *mp) { spppstr_t *sps; sppa_t *ppa; ASSERT(q != NULL && q->q_ptr != NULL); sps = (spppstr_t *)q->q_ptr; ASSERT(IS_SPS_PROMISC(sps)); ASSERT(mp != NULL && mp->b_rptr != NULL); ppa = sps->sps_ppa; sps->sps_flags &= ~SPS_PROMISC; /* * We can't be guaranteed that the sps_ppa field is still valid, since * the control stream might have been closed earlier, in which case * the close procedure would have NULL'd out the sps_ppa. */ if (ppa != NULL) { rw_enter(&ppa->ppa_sib_lock, RW_WRITER); ASSERT(ppa->ppa_promicnt > 0); ppa->ppa_promicnt--; rw_exit(&ppa->ppa_sib_lock); } DBGDLPI((CE_CONT, "/%d: promiscuous mode off\n", sps->sps_mn_id)); dlokack(q, mp, DL_PROMISCOFF_REQ); }
/* * DL_ENABMULTI_REQ */ static void proto_enabmulti_req(dld_str_t *dsp, mblk_t *mp) { dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)mp->b_rptr; int err = 0; t_uscalar_t dl_err; queue_t *q = dsp->ds_wq; mac_perim_handle_t mph; if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { dl_err = DL_OUTSTATE; goto failed; } if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) || !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { dl_err = DL_BADPRIM; goto failed; } mac_perim_enter_by_mh(dsp->ds_mh, &mph); if ((dsp->ds_dmap == NULL) && (err = dls_active_set(dsp)) != 0) { dl_err = DL_SYSERR; goto failed2; } err = dls_multicst_add(dsp, mp->b_rptr + dlp->dl_addr_offset); if (err != 0) { switch (err) { case EINVAL: dl_err = DL_BADADDR; err = 0; break; case ENOSPC: dl_err = DL_TOOMANY; err = 0; break; default: dl_err = DL_SYSERR; break; } if (dsp->ds_dmap == NULL) dls_active_clear(dsp, B_FALSE); goto failed2; } mac_perim_exit(mph); dlokack(q, mp, DL_ENABMULTI_REQ); return; failed2: mac_perim_exit(mph); failed: dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err); }
/********************************************************************** *%FUNCTION: openInterface *%ARGUMENTS: * ifname -- name of interface * type -- Ethernet frame type * hwaddr -- if non-NULL, set to the hardware address *%RETURNS: * A raw socket for talking to the Ethernet card. Exits on error. *%DESCRIPTION: * Opens a raw Ethernet socket ***********************************************************************/ int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { int fd; long buf[MAXDLBUF]; union DL_primitives *dlp; char base_dev[PATH_MAX]; int ppa; if(strlen(ifname) > PATH_MAX) { fatallog("openInterface: interface name too long"); } ppa = atoi(&ifname[strlen(ifname)-1]); strncpy(base_dev, ifname, PATH_MAX); base_dev[strlen(base_dev)-1] = '\0'; /* rearranged order of DLPI code - delphys 20010803 */ dlp = (union DL_primitives*) buf; if (( fd = open(base_dev, O_RDWR)) < 0) { /* Give a more helpful message for the common error case */ if (errno == EPERM) { fatallog("Cannot create raw socket -- pppoe must be run as root."); } fatallog("open(%s): %m", base_dev); } /* rearranged order of DLPI code - delphys 20010803 */ dlattachreq(fd, ppa); dlokack(fd, (char *)buf); dlbindreq(fd, type, 0, DL_CLDLS, 0, 0); dlbindack(fd, (char *)buf); dlinforeq(fd); dlinfoack(fd, (char *)buf); dl_abssaplen = ABS(dlp->info_ack.dl_sap_length); dl_saplen = dlp->info_ack.dl_sap_length; if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen)) fatallog("invalid destination physical address length"); dl_addrlen = dl_abssaplen + ETHERADDRL; /* ethernet address retrieved as part of DL_INFO_ACK - delphys 20010803 */ memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL); if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) { fatallog("DLIOCRAW: %m"); } if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatallog("I_FLUSH: %m"); return fd; }
static int dl_doattach(int fd, int ppa, char *ebuf) { bpf_u_int32 buf[MAXDLBUF]; if (dlattachreq(fd, ppa, ebuf) < 0 || dlokack(fd, "attach", (char *)buf, ebuf) < 0) return (-1); return (0); }
/* * Enable DLPI passive mode. We do not care if this request fails, as this * indicates the underlying DLPI device does not support link aggregation. */ static void dlpassive(int fd, char *ebuf) { dl_passive_req_t req; bpf_u_int32 buf[MAXDLBUF]; req.dl_primitive = DL_PASSIVE_REQ; if (send_request(fd, (char *)&req, sizeof(req), "dlpassive", ebuf) == 0) (void) dlokack(fd, "dlpassive", (char *)buf, ebuf); }
/* * sppp_dl_unbind() * * MT-Perimeters: * exclusive inner, shared outer. * * Description: * Called by qwriter (INNER) from sppp_dlunbindreq as the result of * receiving a DL_UNBIND_REQ message. */ static void sppp_dl_unbind(queue_t *q, mblk_t *mp) { spppstr_t *sps; sppa_t *ppa; t_scalar_t sap; mblk_t *msg; boolean_t saydown; ASSERT(q != NULL && q->q_ptr != NULL); sps = (spppstr_t *)q->q_ptr; ppa = sps->sps_ppa; ASSERT(mp != NULL && mp->b_rptr != NULL); sap = sps->sps_sap; ASSERT((sap == PPP_IP) || (sap == PPP_IPV6) || (sap == PPP_ALLSAP)); /* Flush messages on unbind, per DLPI specification. */ flushq(WR(q), FLUSHALL); flushq(RD(q), FLUSHALL); if ((ppa != NULL) && IS_SPS_CACHED(sps)) { sps->sps_flags &= ~SPS_CACHED; msg = NULL; saydown = (ppa->ppa_ctl != NULL && (sps->sps_npmode == NPMODE_PASS || sps->sps_npmode == NPMODE_QUEUE)); if (sap == PPP_IP) { ppa->ppa_ip_cache = NULL; if (saydown) msg = create_lsmsg(PPP_LINKSTAT_IPV4_UNBOUND); } else if (sap == PPP_IPV6) { ppa->ppa_ip6_cache = NULL; if (saydown) msg = create_lsmsg(PPP_LINKSTAT_IPV6_UNBOUND); } if (msg != NULL) { #ifdef DBG_DLPI cmn_err(CE_CONT, "sending up %s\n", ((sap == PPP_IP) ? "PPP_LINKSTAT_IPV4_UNBOUND" : "PPP_LINKSTAT_IPV6_UNBOUND")); #endif putnext(ppa->ppa_ctl->sps_rq, msg); } } DBGDLPI((CE_CONT, "/%d: unbound from sap %X (req %X)\n", sps->sps_mn_id, sps->sps_sap, sps->sps_req_sap)); sps->sps_req_sap = 0; sps->sps_sap = -1; sps->sps_dlstate = DL_UNBOUND; dlokack(q, mp, DL_UNBIND_REQ); }
/* ARGSUSED */ static void sppp_dl_detach_upper(queue_t *q, mblk_t *mp) { spppstr_t *sps; ASSERT(q != NULL && q->q_ptr != NULL); ASSERT(mp != NULL && mp->b_rptr != NULL); sps = (spppstr_t *)q->q_ptr; /* * We don't actually detach from the PPA until closed or * reattached. */ sps->sps_flags &= ~SPS_PROMISC; /* clear flag anyway */ sps->sps_dlstate = DL_UNATTACHED; dlokack(q, mp, DL_DETACH_REQ); }
static int dlpromiscon(pcap_t *p, bpf_u_int32 level) { dl_promiscon_req_t req; bpf_u_int32 buf[MAXDLBUF]; int err; req.dl_primitive = DL_PROMISCON_REQ; req.dl_level = level; if (send_request(p->fd, (char *)&req, sizeof(req), "promiscon", p->errbuf) < 0) return (PCAP_ERROR); err = dlokack(p->fd, "promiscon" STRINGIFY(level), (char *)buf, p->errbuf); if (err < 0) return (err); return (0); }
/* * DL_ATTACH_REQ */ static void proto_attach_req(dld_str_t *dsp, mblk_t *mp) { dl_attach_req_t *dlp = (dl_attach_req_t *)mp->b_rptr; int err = 0; t_uscalar_t dl_err; queue_t *q = dsp->ds_wq; if (MBLKL(mp) < sizeof (dl_attach_req_t) || dlp->dl_ppa < 0 || dsp->ds_style == DL_STYLE1) { dl_err = DL_BADPRIM; goto failed; } if (dsp->ds_dlstate != DL_UNATTACHED) { dl_err = DL_OUTSTATE; goto failed; } dsp->ds_dlstate = DL_ATTACH_PENDING; err = dld_str_attach(dsp, dlp->dl_ppa); if (err != 0) { switch (err) { case ENOENT: dl_err = DL_BADPPA; err = 0; break; default: dl_err = DL_SYSERR; break; } dsp->ds_dlstate = DL_UNATTACHED; goto failed; } ASSERT(dsp->ds_dlstate == DL_UNBOUND); dlokack(q, mp, DL_ATTACH_REQ); return; failed: dlerrorack(q, mp, DL_ATTACH_REQ, dl_err, (t_uscalar_t)err); }
/* * sppp_dlpromisconreq() * * MT-Perimeters: * shared inner, shared outer. * * Description: * Perform DL_PROMISCON_REQ request, called by sppp_mproto. */ static int sppp_dlpromisconreq(queue_t *q, mblk_t *mp, spppstr_t *sps) { t_uscalar_t level; ASSERT(q != NULL && q->q_ptr != NULL); ASSERT(mp != NULL && mp->b_rptr != NULL); level = ((dl_promiscon_req_t *)mp->b_rptr)->dl_level; ASSERT(sps != NULL); /* snoop issues DL_PROMISCON_REQ more than once. */ if (IS_SPS_PROMISC(sps)) { dlokack(q, mp, DL_PROMISCON_REQ); } else if ((level != DL_PROMISC_PHYS) && (level != DL_PROMISC_SAP) && (level != DL_PROMISC_MULTI)) { DBGERROR((CE_CONT, "DLPI promiscon: bad level %d\n", level)); dlerrorack(q, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 0); } else { qwriter(q, mp, sppp_dl_promiscon, PERIM_INNER); } return (0); }
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); }
/********************************************************************** *%FUNCTION: main *%ARGUMENTS: * argc, argv -- count and values of command-line arguments *%RETURNS: * Nothing *%DESCRIPTION: * Main program ***********************************************************************/ int main(int argc, char *argv[]) { int opt; int sock; PPPoEPacket pkt; int size; #ifdef USE_DLPI long buf[MAXDLBUF]; #endif if (getuid() != geteuid() || getgid() != getegid()) { fprintf(stderr, "SECURITY WARNING: pppoe-sniff will NOT run suid or sgid. Fix your installation.\n"); exit(1); } while((opt = getopt(argc, argv, "I:V")) != -1) { switch(opt) { case 'I': SET_STRING(IfName, optarg); break; case 'V': printf("pppoe-sniff: Roaring Penguin PPPoE Version %s\n", VERSION); exit(0); default: usage(argv[0]); } } /* Pick a default interface name */ if (!IfName) { IfName = DEFAULT_IF; } /* Open the interface */ #ifdef USE_DLPI sock = openInterface(IfName, Eth_PPPOE_Discovery, NULL); dlpromisconreq(sock, DL_PROMISC_PHYS); dlokack(sock, (char *)buf); dlpromisconreq(sock, DL_PROMISC_SAP); dlokack(sock, (char *)buf); #else sock = openInterface(IfName, ETH_P_ALL, NULL); #endif /* We assume interface is in promiscuous mode -- use ifconfig to ensure this */ fprintf(stderr, "Sniffing for PADR. Start your connection on another machine...\n"); while (!SeenPADR) { if (receivePacket(sock, &pkt, &size) < 0) continue; if (ntohs(pkt.length) + HDR_SIZE > size) continue; if (pkt.ver != 1 || pkt.type != 1) continue; if (pkt.code != CODE_PADR) continue; /* Looks promising... parse it */ if (parsePacket(&pkt, parsePADRTags, NULL) < 0) { continue; } DiscType = ntohs(pkt.ethHdr.h_proto); fprintf(stderr, "\nExcellent! Sniffed a likely-looking PADR.\n"); break; } while (!SeenSess) { if (receivePacket(sock, &pkt, &size) < 0) continue; if (ntohs(pkt.length) + HDR_SIZE > size) continue; if (pkt.ver != 1 || pkt.type != 1) continue; if (pkt.code != CODE_SESS) continue; /* Cool! */ SessType = ntohs(pkt.ethHdr.h_proto); break; } fprintf(stderr, "Wonderful! Sniffed a likely-looking session packet.\n"); if ((ServiceName == NULL || *ServiceName == 0) && DiscType == ETH_PPPOE_DISCOVERY && SessType == ETH_PPPOE_SESSION) { fprintf(stderr, "\nGreat! It looks like a standard PPPoE service.\nYou should not need anything special in the configuration file.\n"); return 0; } fprintf(stderr, "\nOK, looks like you need something special in the configuration file.\nTry this:\n\n"); if (ServiceName != NULL && *ServiceName != 0) { fprintf(stderr, "SERVICENAME='%s'\n", ServiceName); } if (DiscType != ETH_PPPOE_DISCOVERY || SessType != ETH_PPPOE_SESSION) { fprintf(stderr, " PPPOE_EXTRA='-f %x:%x'\n", DiscType, SessType); } 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); }
int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { int fd; long buf[MAXDLBUF]; union DL_primitives *dlp; char base_dev[PATH_MAX]; int ppa; if(strlen(ifname) > PATH_MAX) { rp_fatal("socket: Interface name too long"); } if (strlen(ifname) < 2) { rp_fatal("socket: Interface name too short"); } ppa = atoi(&ifname[strlen(ifname)-1]); strncpy(base_dev, ifname, PATH_MAX); base_dev[strlen(base_dev)-1] = '\0'; dlp = (union DL_primitives*) buf; if ( (fd = open(base_dev, O_RDWR)) < 0) { if (errno == EPERM) { rp_fatal("Cannot create raw socket -- pppoe must be run as root."); } if (errno == ENOENT) { char ifname[512]; snprintf(ifname, sizeof(ifname), "/dev/%s", base_dev); if ((fd = open(ifname, O_RDWR)) < 0) { if (errno == EPERM) { rp_fatal("Cannot create raw socket -- pppoe must be run as root."); } } } } if (fd < 0) { fatalSys("socket"); } dlattachreq(fd, ppa); dlokack(fd, (char *)buf); dlbindreq(fd, type, 0, DL_CLDLS, 0, 0); dlbindack(fd, (char *)buf); dlinforeq(fd); dlinfoack(fd, (char *)buf); dl_abssaplen = ABS(dlp->info_ack.dl_sap_length); dl_saplen = dlp->info_ack.dl_sap_length; if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen)) fatalSys("invalid destination physical address length"); dl_addrlen = dl_abssaplen + ETHERADDRL; memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL); if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) { fatalSys("DLIOCRAW"); } if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH"); return fd; }
/* * DL_SET_PHYS_ADDR_REQ */ static void proto_setphysaddr_req(dld_str_t *dsp, mblk_t *mp) { dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)mp->b_rptr; int err = 0; t_uscalar_t dl_err; queue_t *q = dsp->ds_wq; mac_perim_handle_t mph; if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { dl_err = DL_OUTSTATE; goto failed; } if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) || !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { dl_err = DL_BADPRIM; goto failed; } mac_perim_enter_by_mh(dsp->ds_mh, &mph); if ((err = dls_active_set(dsp)) != 0) { dl_err = DL_SYSERR; goto failed2; } /* * If mac-nospoof is enabled and the link is owned by a * non-global zone, changing the mac address is not allowed. */ if (dsp->ds_dlp->dl_zid != GLOBAL_ZONEID && mac_protect_enabled(dsp->ds_mch, MPT_MACNOSPOOF)) { dls_active_clear(dsp, B_FALSE); err = EACCES; goto failed2; } err = mac_unicast_primary_set(dsp->ds_mh, mp->b_rptr + dlp->dl_addr_offset); if (err != 0) { switch (err) { case EINVAL: dl_err = DL_BADADDR; err = 0; break; default: dl_err = DL_SYSERR; break; } dls_active_clear(dsp, B_FALSE); goto failed2; } mac_perim_exit(mph); dlokack(q, mp, DL_SET_PHYS_ADDR_REQ); return; failed2: mac_perim_exit(mph); failed: dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err); }
/* * sppp_dl_attach_upper() * * MT-Perimeters: * exclusive inner, exclusive outer. * * Description: * Called by qwriter (INNER) from sppp_dlattachreq as the result of * receiving a DL_ATTACH_REQ message. */ static void sppp_dl_attach_upper(queue_t *q, mblk_t *mp) { sppa_t *ppa; spppstr_t *sps = q->q_ptr; union DL_primitives *dlp; int err = ENOMEM; cred_t *cr; zoneid_t zoneid; ASSERT(!IS_SPS_PIOATTACH(sps)); dlp = (union DL_primitives *)mp->b_rptr; /* If there's something here, it's detached. */ if (sps->sps_ppa != NULL) { sppp_remove_ppa(sps); } if ((cr = msg_getcred(mp, NULL)) == NULL) zoneid = sps->sps_zoneid; else zoneid = crgetzoneid(cr); ppa = sppp_find_ppa(dlp->attach_req.dl_ppa); if (ppa == NULL) { ppa = sppp_create_ppa(dlp->attach_req.dl_ppa, zoneid); } else if (ppa->ppa_zoneid != zoneid) { ppa = NULL; err = EPERM; } /* * If we can't find or create it, then it's either because we're out of * memory or because the requested PPA is owned by a different zone. */ if (ppa == NULL) { DBGERROR((CE_CONT, "DLPI attach: cannot create ppa %u\n", dlp->attach_req.dl_ppa)); dlerrorack(q, mp, dlp->dl_primitive, DL_SYSERR, err); return; } /* * Preallocate the hangup message so that we're always able to * send this upstream in the event of a catastrophic failure. */ if ((sps->sps_hangup = allocb(1, BPRI_MED)) == NULL) { DBGERROR((CE_CONT, "DLPI attach: cannot allocate hangup\n")); dlerrorack(q, mp, dlp->dl_primitive, DL_SYSERR, ENOSR); return; } sps->sps_dlstate = DL_UNBOUND; sps->sps_ppa = ppa; /* * Add this stream to the head of the list of sibling streams * which belong to the specified ppa. */ rw_enter(&ppa->ppa_sib_lock, RW_WRITER); ppa->ppa_refcnt++; sps->sps_nextsib = ppa->ppa_streams; ppa->ppa_streams = sps; /* * And if this stream was marked as promiscuous (SPS_PROMISC), then we * need to update the promiscuous streams count. This should only * happen when DL_PROMISCON_REQ was issued prior to attachment. */ if (IS_SPS_PROMISC(sps)) { ppa->ppa_promicnt++; } rw_exit(&ppa->ppa_sib_lock); DBGDLPI((CE_CONT, "/%d: attached to ppa %d\n", sps->sps_mn_id, ppa->ppa_ppa_id)); dlokack(q, mp, DL_ATTACH_REQ); }
/* * DL_PROMISCOFF_REQ */ static void proto_promiscoff_req(dld_str_t *dsp, mblk_t *mp) { dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)mp->b_rptr; int err = 0; t_uscalar_t dl_err; uint32_t promisc_saved; queue_t *q = dsp->ds_wq; mac_perim_handle_t mph; if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { dl_err = DL_BADPRIM; goto failed; } if (dsp->ds_dlstate == DL_UNATTACHED || DL_ACK_PENDING(dsp->ds_dlstate)) { dl_err = DL_OUTSTATE; goto failed; } promisc_saved = dsp->ds_promisc; switch (dlp->dl_level) { case DL_PROMISC_SAP: if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) { dl_err = DL_NOTENAB; goto failed; } dsp->ds_promisc &= ~DLS_PROMISC_SAP; break; case DL_PROMISC_MULTI: if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) { dl_err = DL_NOTENAB; goto failed; } dsp->ds_promisc &= ~DLS_PROMISC_MULTI; break; case DL_PROMISC_PHYS: if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) { dl_err = DL_NOTENAB; goto failed; } dsp->ds_promisc &= ~DLS_PROMISC_PHYS; break; default: dl_err = DL_NOTSUPPORTED; goto failed; } mac_perim_enter_by_mh(dsp->ds_mh, &mph); /* * Adjust channel promiscuity. */ err = dls_promisc(dsp, promisc_saved); if (err != 0) { mac_perim_exit(mph); dl_err = DL_SYSERR; goto failed; } if (dsp->ds_promisc == 0) dls_active_clear(dsp, B_FALSE); mac_perim_exit(mph); dlokack(q, mp, DL_PROMISCOFF_REQ); return; failed: dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err); }
int libnet_open_link(libnet_t *l) { register char *cp; char *eos; register int ppa; register dl_info_ack_t *infop; bpf_u_int32 buf[MAXDLBUF]; char dname[100]; #ifndef HAVE_DEV_DLPI char dname2[100]; #endif if (l == NULL) { return (-1); } /* * Determine device and ppa */ cp = strpbrk(l->device, "0123456789"); if (cp == NULL) { sprintf(l->err_buf, "%s missing unit number", l->device); goto bad; } ppa = strtol(cp, &eos, 10); if (*eos != '\0') { snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "libnet_open_link: %s bad unit number", l->device); goto bad; } if (*(l->device) == '/') { memset(&dname, 0, sizeof(dname)); strncpy(dname, l->device, sizeof(dname) - 1); } else { sprintf(dname, "%s/%s", DLPI_DEV_PREFIX, l->device); } #ifdef HAVE_DEV_DLPI /* * Map network device to /dev/dlpi unit */ cp = "/dev/dlpi"; l->fd = open(cp, O_RDWR); if (l->fd == -1) { snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "libnet_open_link: %s: %s", cp, strerror(errno)); goto bad; } /* * Map network interface to /dev/dlpi unit */ ppa = get_dlpi_ppa(l->fd, dname, ppa, l->err_buf); if (ppa < 0) { goto bad; } #else /* * Try device without unit number */ strcpy(dname2, dname); cp = strchr(dname, *cp); *cp = '\0'; l->fd = open(dname, O_RDWR); if (l->fd == -1) { if (errno != ENOENT) { snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "libnet_open_link: %s: %s", dname, strerror(errno)); goto bad; } /* * Try again with unit number */ l->fd = open(dname2, O_RDWR); if (l->fd == -1) { snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "libnet_open_link: %s: %s", dname2, strerror(errno)); goto bad; } cp = dname2; while (*cp && !isdigit((int)*cp)) cp++; if (*cp) ppa = atoi(cp); else /* * XXX Assume unit zero */ ppa = 0; } #endif /* * Attach if "style 2" provider */ if (dlinforeq(l->fd, l->err_buf) < 0 || dlinfoack(l->fd, (char *)buf, l->err_buf) < 0) { goto bad; } infop = &((union DL_primitives *)buf)->info_ack; if (infop->dl_provider_style == DL_STYLE2 && (dlattachreq(l->fd, ppa, l->err_buf) < 0 || dlokack(l->fd, "attach", (char *)buf, l->err_buf) < 0)) { goto bad; } /* * Bind HP-UX 9 and HP-UX 10.20 */ #if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20) || defined(HAVE_HPUX11) || defined(HAVE_SOLARIS) if (dlbindreq(l->fd, 0, l->err_buf) < 0 || dlbindack(l->fd, (char *)buf, l->err_buf) < 0) { goto bad; } #endif /* * Determine link type */ if (dlinforeq(l->fd, l->err_buf) < 0 || dlinfoack(l->fd, (char *)buf, l->err_buf) < 0) { goto bad; } infop = &((union DL_primitives *)buf)->info_ack; switch (infop->dl_mac_type) { case DL_CSMACD: case DL_ETHER: l->link_type = DLT_EN10MB; l->link_offset = 0xe; break; case DL_FDDI: l->link_type = DLT_FDDI; l->link_offset = 0x15; break; default: sprintf(l->err_buf, "libnet_open_link: unknown mac type 0x%lu", (unsigned long) infop->dl_mac_type); goto bad; } #ifdef DLIOCRAW /* * This is a non standard SunOS hack to get the ethernet header. */ if (strioctl(l->fd, DLIOCRAW, 0, NULL) < 0) { sprintf(l->err_buf, "libnet_open_link: DLIOCRAW: %s", strerror(errno)); goto bad; } #endif return (1); bad: if (l->fd > 0) { close(l->fd); /* this can fail ok */ } return (-1); }
pcap_t * pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) { register char *cp; char *eos; register pcap_t *p; register int ppa; register dl_info_ack_t *infop; #ifdef HAVE_SYS_BUFMOD_H bpf_u_int32 ss, flag; #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) { strcpy(ebuf, pcap_strerror(errno)); return (NULL); } memset(p, 0, sizeof(*p)); /* ** Determine device and ppa */ cp = strpbrk(device, "0123456789"); if (cp == NULL) { sprintf(ebuf, "%s missing unit number", device); goto bad; } ppa = strtol(cp, &eos, 10); if (*eos != '\0') { sprintf(ebuf, "%s bad unit number", device); goto bad; } if (*device == '/') strcpy(dname, device); else sprintf(dname, "%s/%s", PCAP_DEV_PREFIX, device); #ifdef HAVE_DEV_DLPI /* Map network device to /dev/dlpi unit */ cp = "/dev/dlpi"; if ((p->fd = open(cp, O_RDWR)) < 0) { sprintf(ebuf, "%s: %s", cp, pcap_strerror(errno)); goto bad; } /* Map network interface to /dev/dlpi unit */ ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf); if (ppa < 0) goto bad; #else /* Try device without unit number */ strcpy(dname2, dname); cp = strchr(dname, *cp); *cp = '\0'; if ((p->fd = open(dname, O_RDWR)) < 0) { if (errno != ENOENT) { sprintf(ebuf, "%s: %s", dname, pcap_strerror(errno)); goto bad; } /* Try again with unit number */ if ((p->fd = open(dname2, O_RDWR)) < 0) { sprintf(ebuf, "%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; if (infop->dl_provider_style == DL_STYLE2 && (dlattachreq(p->fd, ppa, ebuf) < 0 || dlokack(p->fd, "attach", (char *)buf, ebuf) < 0)) goto bad; /* ** Bind (defer if using HP-UX 9 or HP-UX 10.20, totally skip if ** using SINIX) */ #if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20) && !defined(sinix) if (dlbindreq(p->fd, 0, ebuf) < 0 || dlbindack(p->fd, (char *)buf, ebuf) < 0) goto bad; #endif if (promisc) { /* ** Enable promiscuous */ 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) */ #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 (when not in promiscuous mode when using ** using HP-UX and never under SINIX) */ #ifndef sinix if ( #ifdef __hpux !promisc && #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 /* ** HP-UX 9 and HP-UX 10.20 must bind after setting promiscuous ** options) */ #if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20) if (dlbindreq(p->fd, 0, ebuf) < 0 || dlbindack(p->fd, (char *)buf, ebuf) < 0) goto bad; #endif /* ** Determine link type */ 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; break; case DL_FDDI: p->linktype = DLT_FDDI; p->offset = 3; break; default: sprintf(ebuf, "unknown mac type 0x%lu", infop->dl_mac_type); goto bad; } #ifdef DLIOCRAW /* ** This is a non standard SunOS hack to get the ethernet header. */ if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { sprintf(ebuf, "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) { sprintf(ebuf, "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) { sprintf(ebuf, "SBIOCSSNAP: %s", pcap_strerror(errno)); goto bad; } /* ** Set up the bufmod flags */ if (strioctl(p->fd, SBIOCGFLAGS, sizeof(flag), (char *)&flag) < 0) { sprintf(ebuf, "SBIOCGFLAGS: %s", pcap_strerror(errno)); goto bad; } flag |= SB_NO_DROPS; if (strioctl(p->fd, SBIOCSFLAGS, sizeof(flag), (char *)&flag) != 0) { sprintf(ebuf, "SBIOCSFLAGS: %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) { sprintf(ebuf, "SBIOCSTIME: %s", pcap_strerror(errno)); goto bad; } } #endif /* ** As the last operation flush the read side. */ if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { sprintf(ebuf, "FLUSHR: %s", pcap_strerror(errno)); goto bad; } /* Allocate data buffer */ p->bufsize = MAXDLBUF * sizeof(bpf_u_int32); p->buffer = (u_char *)malloc(p->bufsize + p->offset); return (p); bad: free(p); return (NULL); }