📄 ppp.c
字号:
* has dropped below the low-water mark. */ if (us->lowerq != 0) qenable(RD(us->lowerq)); } else { /* * A network protocol stream. Put a DLPI header on each * packet and send it on. * (Actually, it seems that the IP module will happily * accept M_DATA messages without the DL_UNITDATA_IND header.) */ while ((mp = getq(q)) != 0) { if (!canputnext(q)) { putbq(q, mp); break; }#ifndef NO_DLPI proto = PPP_PROTOCOL(mp->b_rptr); mp->b_rptr += PPP_HDRLEN; hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint), BPRI_MED); if (hdr == 0) { /* XXX should put it back and use bufcall */ freemsg(mp); continue; } hdr->b_datap->db_type = M_PROTO; ud = (dl_unitdata_ind_t *) hdr->b_wptr; hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint); hdr->b_cont = mp; ud->dl_primitive = DL_UNITDATA_IND; ud->dl_dest_addr_length = sizeof(uint); ud->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t); ud->dl_src_addr_length = sizeof(uint); ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(uint);#if DL_CURRENT_VERSION >= 2 ud->dl_group_address = 0;#endif /* Send the DLPI client the data with the SAP they requested, (e.g. ETHERTYPE_IP) rather than the PPP protocol number (e.g. PPP_IP) */ ((uint *)(ud + 1))[0] = us->req_sap; /* dest SAP */ ((uint *)(ud + 1))[1] = us->req_sap; /* src SAP */ putnext(q, hdr);#else /* NO_DLPI */ putnext(q, mp);#endif /* NO_DLPI */ } /* * Now that we have consumed some packets from this queue, * enable the control stream's read service routine so that we * can process any packets for us that might have got queued * there for flow control reasons. */ if (us->ppa) qenable(us->ppa->q); } return 0;}static upperstr_t *find_dest(ppa, proto) upperstr_t *ppa; int proto;{ upperstr_t *us; for (us = ppa->next; us != 0; us = us->next) if (proto == us->sap) break; return us;}#if defined (SOL2)/* * Test upstream promiscuous conditions. As of now, only pass IPv4 and * Ipv6 packets upstream (let PPP packets be decoded elsewhere). */static upperstr_t *find_promisc(us, proto) upperstr_t *us; int proto;{ if ((proto != PPP_IP) && (proto != PPP_IPV6)) return (upperstr_t *)0; for ( ; us; us = us->next) { if ((us->flags & US_PROMISC) && (us->state == DL_IDLE)) return us; } return (upperstr_t *)0;}/* * Prepend an empty Ethernet header to msg for snoop, et al. */static mblk_t *prepend_ether(us, mp, proto) upperstr_t *us; mblk_t *mp; int proto;{ mblk_t *eh; int type; if ((eh = allocb(sizeof(struct ether_header), BPRI_HI)) == 0) { freemsg(mp); return (mblk_t *)0; } if (proto == PPP_IP) type = ETHERTYPE_IP; else if (proto == PPP_IPV6) type = ETHERTYPE_IPV6; else type = proto; /* What else? Let decoder decide */ eh->b_wptr += sizeof(struct ether_header); bzero((caddr_t)eh->b_rptr, sizeof(struct ether_header)); ((struct ether_header *)eh->b_rptr)->ether_type = htons((short)type); eh->b_cont = mp; return (eh);}/* * Prepend DL_UNITDATA_IND mblk to msg */static mblk_t *prepend_udind(us, mp, proto) upperstr_t *us; mblk_t *mp; int proto;{ dl_unitdata_ind_t *dlu; mblk_t *dh; size_t size; size = sizeof(dl_unitdata_ind_t); if ((dh = allocb(size, BPRI_MED)) == 0) { freemsg(mp); return (mblk_t *)0; } dh->b_datap->db_type = M_PROTO; dh->b_wptr = dh->b_datap->db_lim; dh->b_rptr = dh->b_wptr - size; dlu = (dl_unitdata_ind_t *)dh->b_rptr; dlu->dl_primitive = DL_UNITDATA_IND; dlu->dl_dest_addr_length = 0; dlu->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t); dlu->dl_src_addr_length = 0; dlu->dl_src_addr_offset = sizeof(dl_unitdata_ind_t); dlu->dl_group_address = 0; dh->b_cont = mp; return (dh);}/* * For any recognized promiscuous streams, send data upstream */static voidpromisc_sendup(ppa, mp, proto, skip) upperstr_t *ppa; mblk_t *mp; int proto, skip;{ mblk_t *dup_mp, *dup_dup_mp; upperstr_t *prus, *nprus; if ((prus = find_promisc(ppa, proto)) != 0) { if (dup_mp = dupmsg(mp)) { if (skip) dup_mp->b_rptr += PPP_HDRLEN; for ( ; nprus = find_promisc(prus->next, proto); prus = nprus) { if (dup_dup_mp = dupmsg(dup_mp)) { if (canputnext(prus->q)) { if (prus->flags & US_RAWDATA) { dup_dup_mp = prepend_ether(prus, dup_dup_mp, proto); putnext(prus->q, dup_dup_mp); } else { dup_dup_mp = prepend_udind(prus, dup_dup_mp, proto); putnext(prus->q, dup_dup_mp); } } else { DPRINT("ppp_urput: data to promisc q dropped\n"); freemsg(dup_dup_mp); } } } if (canputnext(prus->q)) { if (prus->flags & US_RAWDATA) { dup_mp = prepend_ether(prus, dup_mp, proto); putnext(prus->q, dup_mp); } else { dup_mp = prepend_udind(prus, dup_mp, proto); putnext(prus->q, dup_mp); } } else { DPRINT("ppp_urput: data to promisc q dropped\n"); freemsg(dup_mp); } } }}#endif /* defined(SOL2) *//* * We simply put the message on to the associated upper control stream * (either here or in ppplrsrv). That way we enter the perimeters * before looking through the list of attached streams to decide which * stream it should go up. */static intppplrput(q, mp) queue_t *q; mblk_t *mp;{ queue_t *uq; struct iocblk *iop; switch (mp->b_datap->db_type) { case M_IOCTL: iop = (struct iocblk *) mp->b_rptr; iop->ioc_error = EINVAL; mp->b_datap->db_type = M_IOCNAK; qreply(q, mp); return 0; case M_FLUSH: if (*mp->b_rptr & FLUSHR) flushq(q, FLUSHDATA); if (*mp->b_rptr & FLUSHW) { *mp->b_rptr &= ~FLUSHR; qreply(q, mp); } else freemsg(mp); return 0; } /* * If we can't get the lower lock straight away, queue this one * rather than blocking, to avoid the possibility of deadlock. */ if (!TRYLOCK_LOWER_R) { putq(q, mp); return 0; } /* * Check that we're still connected to the driver. */ uq = (queue_t *) q->q_ptr; if (uq == 0) { UNLOCK_LOWER; DPRINT1("ppplrput: q = %x, uq = 0??\n", q); freemsg(mp); return 0; } /* * Try to forward the message to the put routine for the upper * control stream for this lower stream. * If there are already messages queued here, queue this one so * they don't get out of order. */ if (queclass(mp) == QPCTL || (qsize(q) == 0 && canput(uq))) put(uq, mp); else putq(q, mp); UNLOCK_LOWER; return 0;}static intppplrsrv(q) queue_t *q;{ mblk_t *mp; queue_t *uq; /* * Packets get queued here for flow control reasons * or if the lrput routine couldn't get the lower lock * without blocking. */ LOCK_LOWER_R; uq = (queue_t *) q->q_ptr; if (uq == 0) { UNLOCK_LOWER; flushq(q, FLUSHALL); DPRINT1("ppplrsrv: q = %x, uq = 0??\n", q); return 0; } while ((mp = getq(q)) != 0) { if (queclass(mp) == QPCTL || canput(uq)) put(uq, mp); else { putbq(q, mp); break; } } UNLOCK_LOWER; return 0;}static intputctl2(q, type, code, val) queue_t *q; int type, code, val;{ mblk_t *mp; mp = allocb(2, BPRI_HI); if (mp == 0) return 0; mp->b_datap->db_type = type; mp->b_wptr[0] = code; mp->b_wptr[1] = val; mp->b_wptr += 2; putnext(q, mp); return 1;}static intputctl4(q, type, code, val) queue_t *q; int type, code, val;{ mblk_t *mp; mp = allocb(4, BPRI_HI); if (mp == 0) return 0; mp->b_datap->db_type = type; mp->b_wptr[0] = code; ((short *)mp->b_wptr)[1] = val; mp->b_wptr += 4; putnext(q, mp); return 1;}static voiddebug_dump(q, mp) queue_t *q; mblk_t *mp;{ upperstr_t *us; queue_t *uq, *lq; DPRINT("ppp upper streams:\n"); for (us = minor_devs; us != 0; us = us->nextmn) { uq = us->q; DPRINT3(" %d: q=%x rlev=%d", us->mn, uq, (uq? qsize(uq): 0)); DPRINT3(" wlev=%d flags=0x%b", (uq? qsize(WR(uq)): 0), us->flags, "\020\1priv\2control\3blocked\4last"); DPRINT3(" state=%x sap=%x req_sap=%x", us->state, us->sap, us->req_sap); if (us->ppa == 0) DPRINT(" ppa=?\n"); else DPRINT1(" ppa=%d\n", us->ppa->ppa_id); if (us->flags & US_CONTROL) { lq = us->lowerq; DPRINT3(" control for %d lq=%x rlev=%d", us->ppa_id, lq, (lq? qsize(RD(lq)): 0)); DPRINT3(" wlev=%d mru=%d mtu=%d\n", (lq? qsize(lq): 0), us->mru, us->mtu); } } mp->b_datap->db_type = M_IOCACK; qreply(q, mp);}#ifdef FILTER_PACKETS#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/udp.h>#include <netinet/tcp.h>#define MAX_IPHDR 128 /* max TCP/IP header size *//* The following table contains a hard-coded list of protocol/port pairs. * Any matching packets are either discarded unconditionally, or, * if ok_if_link_up is non-zero when a connection does not currently exist * (i.e., they go through if the connection is present, but never initiate * a dial-out). * This idea came from a post by dm@garage.uun.org (David Mazieres) */static struct pktfilt_tab { int proto; u_short port; u_short ok_if_link_up; } pktfilt_tab[] = { { IPPROTO_UDP, 520, 1 }, /* RIP, ok to pass if link is up */ { IPPROTO_UDP, 123, 1 }, /* NTP, don't keep up the link for it */ { -1, 0, 0 } /* terminator entry has port == -1 */};static intip_hard_filter(us, mp, outbound) upperstr_t *us; mblk_t *mp; int outbound;{ struct ip *ip; struct pktfilt_tab *pft; mblk_t *temp_mp; int proto; int len, hlen; /* Note, the PPP header has already been pulled up in all cases */ proto = PPP_PROTOCOL(mp->b_rptr); if (us->flags & US_DBGLOG) DPRINT3("ppp/%d: filter, proto=0x%x, out=%d\n", us->mn, proto, outbound); switch (proto) { case PPP_IP: if ((mp->b_wptr - mp->b_rptr) == PPP_HDRLEN && mp->b_cont != 0) { temp_mp = mp->b_cont; len = msgdsize(temp_mp); hlen = (len < MAX_IPHDR) ? len : MAX_IPHDR; PULLUP(temp_mp, hlen); if (temp_mp == 0) { DPRINT2("ppp/%d: filter, pullup next failed, len=%d\n", us->mn, hlen); mp->b_cont = 0; /* PULLUP() freed the rest */ freemsg(mp); return 0; } ip = (struct ip *)mp->b_cont->b_rptr; } else { len = msgdsize(mp); hlen = (len < (PPP_HDRLEN+MAX_IPHDR)) ? len : (PPP_HDRLEN+MAX_IPHDR); PULLUP(mp, hlen); if (mp == 0) { DPRINT2("ppp/%d: filter, pullup failed, len=%d\n", us->mn, hlen); return 0; } ip = (struct ip *)(mp->b_rptr + PPP_HDRLEN); } /* For IP traffic, certain packets (e.g., RIP) may be either * 1. ignored - dropped completely * 2. will not initiate a connection, but * will be passed if a connection is currently up. */ for (pft=pktfilt_tab; pft->proto != -1; pft++) { if (ip->ip_p == pft->proto) { switch(pft->proto) { case IPPROTO_UDP: if (((struct udphdr *) &((int *)ip)[ip->ip_hl])->uh_dport == htons(pft->port)) goto endfor; break; case IPPROTO_TCP: if (((struct tcphdr *) &((int *)ip)[ip->ip_hl])->th_dport == htons(pft->port)) goto endfor; break; } } } endfor: if (pft->proto != -1) { if (us->flags & US_DBGLOG) DPRINT3("ppp/%d: found IP pkt, proto=0x%x (%d)\n", us->mn, pft->proto, pft->port); /* Discard if not connected, or if not pass_with_link_up */ /* else, if link is up let go by, but don't update time */ return pft->ok_if_link_up? -1: 0; } break; } /* end switch (proto) */ return 1;}#endif /* FILTER_PACKETS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -