X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=modules%2Fppp.c;h=2734cd6aec6a5c7af61acb87c0ee61ca089bec36;hp=0000cb147ac319d7500dd48da87543742ceafd7e;hb=63526107ef91931ac8ef8c242b9cbcdf7da96520;hpb=92c20f261b9618715d6b1579e997e8757a88174e diff --git a/modules/ppp.c b/modules/ppp.c index 0000cb1..2734cd6 100644 --- a/modules/ppp.c +++ b/modules/ppp.c @@ -24,11 +24,11 @@ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * - * $Id: ppp.c,v 1.3 1996/01/01 22:48:39 paulus Exp $ + * $Id: ppp.c,v 1.15 1998/05/04 06:11:35 paulus Exp $ */ /* - * This file is used under Solaris 2, SVR4, and SunOS 4. + * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX. */ #include @@ -37,7 +37,13 @@ #include #include #include +#ifdef __osf__ +#include +#include +#define queclass(mp) ((mp)->b_band & QPCTL) +#else #include +#endif #include #ifdef SVR4 #include @@ -60,6 +66,14 @@ #include #include "ppp_mod.h" +/* + * Modifications marked with #ifdef PRIOQ are for priority queueing of + * interactive traffic, and are due to Marko Zec . + */ +#ifdef PRIOQ +#include +#endif /* PRIOQ */ + #ifdef __STDC__ #define __P(x) x #else @@ -73,10 +87,6 @@ #define ETHERTYPE_IP 0x800 #endif -#ifndef PPP_MAXMTU -#define PPP_MAXMTU 65535 -#endif - extern time_t time; /* @@ -123,6 +133,35 @@ typedef struct upperstr { #define US_LASTMOD 8 /* no PPP modules below us */ #define US_DBGLOG 0x10 /* log various occurrences */ + +#ifdef PRIOQ +static u_char max_band=0; +static u_char def_band=0; + +#define IPPORT_DEFAULT 65535 + +/* + * Port priority table + * Highest priority ports are listed first, lowest are listed last. + * ICMP & packets using unlisted ports will be treated as "default". + * If IPPORT_DEFAULT is not listed here, "default" packets will be + * assigned lowest priority. + * Each line should be terminated with "0". + * Line containing only "0" marks the end of the list. + */ + +static u_short prioq_table[]= { + 113, 53, 0, + 22, 23, 513, 517, 518, 0, + 514, 21, 79, 111, 0, + 25, 109, 110, 0, + IPPORT_DEFAULT, 0, + 20, 70, 80, 8001, 8008, 8080, 0, /* 8001,8008,8080 - common proxy ports */ +0 }; + +#endif /* PRIOQ */ + + static upperstr_t *minor_devs = NULL; static upperstr_t *ppas = NULL; @@ -142,7 +181,7 @@ static int ppplrsrv __P((queue_t *)); static int ppplwsrv __P((queue_t *)); #ifndef NO_DLPI static void dlpi_request __P((queue_t *, mblk_t *, upperstr_t *)); -static void dlpi_error __P((queue_t *, int, int, int)); +static void dlpi_error __P((queue_t *, upperstr_t *, int, int, int)); static void dlpi_ok __P((queue_t *, int)); #endif static int send_data __P((mblk_t *, upperstr_t *)); @@ -153,9 +192,16 @@ static void debug_dump __P((queue_t *, mblk_t *)); static upperstr_t *find_dest __P((upperstr_t *, int)); static int putctl2 __P((queue_t *, int, int, int)); static int putctl4 __P((queue_t *, int, int, int)); +static int pass_packet __P((upperstr_t *ppa, mblk_t *mp, int outbound)); +static int ip_hard_filter __P((upperstr_t *ppa, mblk_t *mp, int outbound)); +#define PPP_ID 0xb1a6 static struct module_info ppp_info = { - 0xb1a6, "ppp", 0, 512, 512, 128 +#ifdef PRIOQ + PPP_ID, "ppp", 0, 512, 512, 384 +#else + PPP_ID, "ppp", 0, 512, 512, 128 +#endif /* PRIOQ */ }; static struct qinit pppurint = { @@ -235,10 +281,37 @@ pppopen(q, dev, oflag, sflag) upperstr_t *up; upperstr_t **prevp; minor_t mn; +#ifdef PRIOQ + u_short *ptr; + u_char new_band; +#endif /* PRIOQ */ if (q->q_ptr) DRV_OPEN_OK(dev); /* device is already open */ +#ifdef PRIOQ + /* Calculate max_bband & def_band from definitions in prioq.h + This colud be done at some more approtiate time (less often) + but this way it works well so I'll just leave it here */ + + max_band = 1; + def_band = 0; + ptr = prioq_table; + while (*ptr) { + new_band = 1; + while (*ptr) + if (*ptr++ == IPPORT_DEFAULT) { + new_band = 0; + def_band = max_band; + } + max_band += new_band; + ptr++; + } + if (def_band) + def_band = max_band - def_band; + --max_band; +#endif /* PRIOQ */ + if (sflag == CLONEOPEN) { mn = 0; for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) { @@ -318,10 +391,12 @@ pppclose(q, flag) qprocsoff(q); up = (upperstr_t *) q->q_ptr; + if (up == 0) { + DPRINT("pppclose: q_ptr = 0\n"); + return 0; + } if (up->flags & US_DBGLOG) DPRINT2("ppp/%d: close, flags=%x\n", up->mn, up->flags); - if (up == 0) - return 0; if (up->flags & US_CONTROL) { #ifdef LACHTCP struct ifstats *ifp, *pifp; @@ -387,7 +462,7 @@ pppclose(q, flag) break; } } - kmem_free(up, sizeof(upperstr_t)); + FREE(up, sizeof(upperstr_t)); --ppp_count; return 0; @@ -415,8 +490,24 @@ pppuwput(q, mp) int error, n, sap; mblk_t *mq; struct ppp_idle *pip; + int len; +#ifdef PRIOQ + queue_t *tlq; +#endif /* PRIOQ */ us = (upperstr_t *) q->q_ptr; + if (us == 0) { + DPRINT("pppuwput: q_ptr = 0!\n"); + return 0; + } + if (mp == 0) { + DPRINT1("pppuwput/%d: mp = 0!\n", us->mn); + return 0; + } + if (mp->b_datap == 0) { + DPRINT1("pppuwput/%d: mp->b_datap = 0!\n", us->mn); + return 0; + } switch (mp->b_datap->db_type) { #ifndef NO_DLPI case M_PCPROTO: @@ -439,8 +530,8 @@ pppuwput(q, mp) break; } #ifdef NO_DLPI - if ((us->flags & US_CONTROL) == 0) - us->ppa->last_sent = time; + if ((us->flags & US_CONTROL) == 0 && !pass_packet(us, mp, 1)) + break; #endif if (!send_data(mp, us)) putq(q, mp); @@ -456,8 +547,16 @@ pppuwput(q, mp) case I_LINK: if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0) break; + if (mp->b_cont == 0) { + DPRINT1("pppuwput/%d: ioctl I_LINK b_cont = 0!\n", us->mn); + break; + } lb = (struct linkblk *) mp->b_cont->b_rptr; us->lowerq = lq = lb->l_qbot; + if (lq == 0) { + DPRINT1("pppuwput/%d: ioctl I_LINK l_qbot = 0!\n", us->mn); + break; + } lq->q_ptr = (caddr_t) us; RD(lq)->q_ptr = (caddr_t) us; noenable(RD(lq)); @@ -472,14 +571,32 @@ pppuwput(q, mp) putctl2(lq, M_CTL, PPPCTL_UNIT, us->ppa_id); putctl4(lq, M_CTL, PPPCTL_MRU, us->mru); putctl4(lq, M_CTL, PPPCTL_MTU, us->mtu); +#ifdef PRIOQ + /* Lower tty driver's queue hiwat/lowat from default 4096/128 + to 256/128 since we don't want queueing of data on + output to physical device */ + + freezestr(lq); + for (tlq = lq; tlq->q_next != NULL; tlq = tlq->q_next) + ; + strqset(tlq, QHIWAT, 0, 256); + strqset(tlq, QLOWAT, 0, 128); + unfreezestr(lq); +#endif /* PRIOQ */ break; case I_UNLINK: + if (mp->b_cont == 0) { + DPRINT1("pppuwput/%d: ioctl I_UNLINK b_cont = 0!\n", us->mn); + break; + } lb = (struct linkblk *) mp->b_cont->b_rptr; #if DEBUG - if (us->lowerq != lb->l_qbot) + if (us->lowerq != lb->l_qbot) { DPRINT2("ppp unlink: lowerq=%x qbot=%x\n", us->lowerq, lb->l_qbot); + break; + } #endif us->lowerq = 0; iop->ioc_count = 0; @@ -519,6 +636,10 @@ pppuwput(q, mp) the stream (like pppstats) */ if (iop->ioc_count != sizeof(int) || us->ppa != 0) break; + if (mp->b_cont == 0) { + DPRINT1("pppuwput/%d: ioctl PPPIO_ATTACH b_cont = 0!\n", us->mn); + break; + } n = *(int *)mp->b_cont->b_rptr; for (ppa = ppas; ppa != 0; ppa = ppa->nextppa) if (ppa->ppa_id == n) @@ -536,6 +657,10 @@ pppuwput(q, mp) /* Attach to a given SAP. */ if (iop->ioc_count != sizeof(int) || us->ppa == 0) break; + if (mp->b_cont == 0) { + DPRINT1("pppuwput/%d: ioctl PPPIO_BIND b_cont = 0!\n", us->mn); + break; + } n = *(int *)mp->b_cont->b_rptr; /* n must be a valid PPP network protocol number. */ if (n < 0x21 || n > 0x3fff || (n & 0x101) != 1) @@ -555,8 +680,12 @@ pppuwput(q, mp) case PPPIO_MRU: if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0) break; + if (mp->b_cont == 0) { + DPRINT1("pppuwput/%d: ioctl PPPIO_MRU b_cont = 0!\n", us->mn); + break; + } n = *(int *)mp->b_cont->b_rptr; - if (n <= 0 || n > PPP_MAXMTU) + if (n <= 0 || n > PPP_MAXMRU) break; if (n < PPP_MRU) n = PPP_MRU; @@ -570,13 +699,16 @@ pppuwput(q, mp) case PPPIO_MTU: if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0) break; + if (mp->b_cont == 0) { + DPRINT1("pppuwput/%d: ioctl PPPIO_MTU b_cont = 0!\n", us->mn); + break; + } n = *(int *)mp->b_cont->b_rptr; if (n <= 0 || n > PPP_MAXMTU) break; - if (n < PPP_MRU) - n = PPP_MRU; us->mtu = n; #ifdef LACHTCP + /* The MTU reported in netstat, not used as IP max packet size! */ us->ifstats.ifs_mtu = n; #endif if (us->lowerq) @@ -593,6 +725,10 @@ pppuwput(q, mp) case PPPIO_DEBUG: if (iop->ioc_count != sizeof(int)) break; + if (mp->b_cont == 0) { + DPRINT1("pppuwput/%d: ioctl PPPIO_DEBUG b_cont = 0!\n", us->mn); + break; + } n = *(int *)mp->b_cont->b_rptr; if (n == PPPDBG_DUMP + PPPDBG_DRIVER) { qwriter(q, NULL, debug_dump, PERIM_OUTER); @@ -616,12 +752,19 @@ pppuwput(q, mp) break; if ((us->flags & US_CONTROL) == 0) break; + if (mp->b_cont == 0) { + DPRINT1("pppuwput/%d: ioctl PPPIO_NPMODE b_cont = 0!\n", us->mn); + break; + } sap = ((int *)mp->b_cont->b_rptr)[0]; for (nps = us->next; nps != 0; nps = nps->next) if (nps->sap == sap) break; - if (nps == 0) + if (nps == 0) { + if (us->flags & US_DBGLOG) + DPRINT2("ppp/%d: no stream for sap %x\n", us->mn, sap); break; + } nps->npmode = (enum NPmode) ((int *)mp->b_cont->b_rptr)[1]; if (nps->npmode == NPMODE_DROP || nps->npmode == NPMODE_ERROR) flushq(WR(nps->q), FLUSHDATA); @@ -654,7 +797,6 @@ pppuwput(q, mp) #ifdef LACHTCP case SIOCSIFNAME: - printf("SIOCSIFNAME\n"); /* Sent from IP down to us. Attach the ifstats structure. */ if (iop->ioc_count != sizeof(struct ifreq) || us->ppa == 0) break; @@ -702,7 +844,6 @@ pppuwput(q, mp) break; case SIOCGIFFLAGS: - printf("SIOCGIFFLAGS\n"); if (!(us->flags & US_CONTROL)) { if (us->ppa) us = us->ppa; @@ -714,7 +855,6 @@ pppuwput(q, mp) break; case SIOCSIFFLAGS: - printf("SIOCSIFFLAGS\n"); if (!(us->flags & US_CONTROL)) { if (us->ppa) us = us->ppa; @@ -726,7 +866,6 @@ pppuwput(q, mp) break; case SIOCSIFADDR: - printf("SIOCSIFADDR\n"); if (!(us->flags & US_CONTROL)) { if (us->ppa) us = us->ppa; @@ -738,6 +877,21 @@ pppuwput(q, mp) error = 0; break; + case SIOCSIFMTU: + /* + * Vanilla SVR4 systems don't handle SIOCSIFMTU, rather + * they take the MTU from the DL_INFO_ACK we sent in response + * to their DL_INFO_REQ. Fortunately, they will update the + * MTU if we send an unsolicited DL_INFO_ACK up. + */ + if ((mq = allocb(sizeof(dl_info_req_t), BPRI_HI)) == 0) + break; /* should do bufcall */ + ((union DL_primitives *)mq->b_rptr)->dl_primitive = DL_INFO_REQ; + mq->b_wptr = mq->b_rptr + sizeof(dl_info_req_t); + dlpi_request(q, mq, us); + error = 0; + break; + case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFADDR: @@ -819,7 +973,7 @@ dlpi_request(q, mp, us) dl_bind_ack_t *ackp; if (us->flags & US_DBGLOG) - cmn_err(CE_CONT, "ppp/%d: dlpi prim %x len=%d\n", us->mn, + DPRINT3("ppp/%d: dlpi prim %x len=%d\n", us->mn, d->dl_primitive, size); switch (d->dl_primitive) { case DL_INFO_REQ: @@ -832,9 +986,9 @@ dlpi_request(q, mp, us) reply->b_wptr += sizeof(dl_info_ack_t); bzero((caddr_t) info, sizeof(dl_info_ack_t)); info->dl_primitive = DL_INFO_ACK; - info->dl_max_sdu = PPP_MAXMTU; + info->dl_max_sdu = us->ppa? us->ppa->mtu: PPP_MAXMTU; info->dl_min_sdu = 1; - info->dl_addr_length = sizeof(ulong); + info->dl_addr_length = sizeof(uint); #ifdef DL_OTHER info->dl_mac_type = DL_OTHER; #else @@ -844,7 +998,7 @@ dlpi_request(q, mp, us) info->dl_service_mode = DL_CLDLS; info->dl_provider_style = DL_STYLE2; #if DL_CURRENT_VERSION >= 2 - info->dl_sap_length = sizeof(ulong); + info->dl_sap_length = sizeof(uint); info->dl_version = DL_CURRENT_VERSION; #endif qreply(q, reply); @@ -854,14 +1008,14 @@ dlpi_request(q, mp, us) if (size < sizeof(dl_attach_req_t)) goto badprim; if (us->state != DL_UNATTACHED || us->ppa != 0) { - dlpi_error(q, DL_ATTACH_REQ, DL_OUTSTATE, 0); + dlpi_error(q, us, DL_ATTACH_REQ, DL_OUTSTATE, 0); break; } for (ppa = ppas; ppa != 0; ppa = ppa->nextppa) if (ppa->ppa_id == d->attach_req.dl_ppa) break; if (ppa == 0) { - dlpi_error(q, DL_ATTACH_REQ, DL_BADPPA, 0); + dlpi_error(q, us, DL_ATTACH_REQ, DL_BADPPA, 0); break; } us->ppa = ppa; @@ -872,7 +1026,7 @@ dlpi_request(q, mp, us) if (size < sizeof(dl_detach_req_t)) goto badprim; if (us->state != DL_UNBOUND || us->ppa == 0) { - dlpi_error(q, DL_DETACH_REQ, DL_OUTSTATE, 0); + dlpi_error(q, us, DL_DETACH_REQ, DL_OUTSTATE, 0); break; } qwriter(q, mp, detach_ppa, PERIM_OUTER); @@ -882,23 +1036,25 @@ dlpi_request(q, mp, us) if (size < sizeof(dl_bind_req_t)) goto badprim; if (us->state != DL_UNBOUND || us->ppa == 0) { - dlpi_error(q, DL_BIND_REQ, DL_OUTSTATE, 0); + dlpi_error(q, us, DL_BIND_REQ, DL_OUTSTATE, 0); break; } +#if 0 + /* apparently this test fails (unnecessarily?) on some systems */ if (d->bind_req.dl_service_mode != DL_CLDLS) { - dlpi_error(q, DL_BIND_REQ, DL_UNSUPPORTED, 0); + dlpi_error(q, us, DL_BIND_REQ, DL_UNSUPPORTED, 0); break; } +#endif /* saps must be valid PPP network protocol numbers, except that we accept ETHERTYPE_IP in place of PPP_IP. */ sap = d->bind_req.dl_sap; us->req_sap = sap; - DPRINT1("ppp bind %x\n", sap); if (sap == ETHERTYPE_IP) sap = PPP_IP; if (sap < 0x21 || sap > 0x3fff || (sap & 0x101) != 1) { - dlpi_error(q, DL_BIND_REQ, DL_BADADDR, 0); + dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0); break; } @@ -907,25 +1063,25 @@ dlpi_request(q, mp, us) if (os->sap == sap) break; if (os != 0) { - dlpi_error(q, DL_BIND_REQ, DL_NOADDR, 0); + dlpi_error(q, us, DL_BIND_REQ, DL_NOADDR, 0); break; } us->sap = sap; us->state = DL_IDLE; - if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(ulong), + if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(uint), BPRI_HI)) == 0) break; /* should do bufcall */ ackp = (dl_bind_ack_t *) reply->b_wptr; - reply->b_wptr += sizeof(dl_bind_ack_t) + sizeof(ulong); + reply->b_wptr += sizeof(dl_bind_ack_t) + sizeof(uint); reply->b_datap->db_type = M_PCPROTO; bzero((caddr_t) ackp, sizeof(dl_bind_ack_t)); ackp->dl_primitive = DL_BIND_ACK; ackp->dl_sap = sap; - ackp->dl_addr_length = sizeof(ulong); + ackp->dl_addr_length = sizeof(uint); ackp->dl_addr_offset = sizeof(dl_bind_ack_t); - *(ulong *)(ackp+1) = sap; + *(uint *)(ackp+1) = sap; qreply(q, reply); break; @@ -933,7 +1089,7 @@ dlpi_request(q, mp, us) if (size < sizeof(dl_unbind_req_t)) goto badprim; if (us->state != DL_IDLE) { - dlpi_error(q, DL_UNBIND_REQ, DL_OUTSTATE, 0); + dlpi_error(q, us, DL_UNBIND_REQ, DL_OUTSTATE, 0); break; } us->sap = -1; @@ -948,7 +1104,7 @@ dlpi_request(q, mp, us) if (size < sizeof(dl_unitdata_req_t)) goto badprim; if (us->state != DL_IDLE) { - dlpi_error(q, DL_UNITDATA_REQ, DL_OUTSTATE, 0); + dlpi_error(q, us, DL_UNITDATA_REQ, DL_OUTSTATE, 0); break; } if ((ppa = us->ppa) == 0) { @@ -960,7 +1116,68 @@ dlpi_request(q, mp, us) DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->mtu); break; } - ppa->last_sent = time; + mp->b_band = 0; +#ifdef PRIOQ + /* Extract s_port & d_port from IP-packet, the code is a bit + dirty here, but so am I, too... */ + if (mp->b_datap->db_type == M_PROTO && us->sap == PPP_IP + && mp->b_cont != 0) { + u_char *bb, *tlh; + int iphlen, len; + u_short *ptr; + u_char band_unset, cur_band, syn; + u_short s_port, d_port; + + bb = mp->b_cont->b_rptr; /* bb points to IP-header*/ + len = mp->b_cont->b_wptr - mp->b_cont->b_rptr; + syn = 0; + s_port = IPPORT_DEFAULT; + d_port = IPPORT_DEFAULT; + if (len >= 20) { /* 20 = minimum length of IP header */ + iphlen = (bb[0] & 0x0f) * 4; + tlh = bb + iphlen; + len -= iphlen; + switch (bb[9]) { + case IPPROTO_TCP: + if (len >= 20) { /* min length of TCP header */ + s_port = (tlh[0] << 8) + tlh[1]; + d_port = (tlh[2] << 8) + tlh[3]; + syn = tlh[13] & 0x02; + } + break; + case IPPROTO_UDP: + if (len >= 8) { /* min length of UDP header */ + s_port = (tlh[0] << 8) + tlh[1]; + d_port = (tlh[2] << 8) + tlh[3]; + } + break; + } + } + + /* + * Now calculate b_band for this packet from the + * port-priority table. + */ + ptr = prioq_table; + cur_band = max_band; + band_unset = 1; + while (*ptr) { + while (*ptr && band_unset) + if (s_port == *ptr || d_port == *ptr++) { + mp->b_band = cur_band; + band_unset = 0; + break; + } + ptr++; + cur_band--; + } + if (band_unset) + mp->b_band = def_band; + /* It may be usable to urge SYN packets a bit */ + if (syn) + mp->b_band++; + } +#endif /* PRIOQ */ /* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */ if (mp->b_datap->db_ref > 1) { np = allocb(PPP_HDRLEN, BPRI_HI); @@ -979,8 +1196,10 @@ dlpi_request(q, mp, us) mp->b_rptr[1] = PPP_UI; mp->b_rptr[2] = us->sap >> 8; mp->b_rptr[3] = us->sap; - if (!send_data(mp, us)) - putq(q, mp); + if (pass_packet(us, mp, 1)) { + if (!send_data(mp, us)) + putq(q, mp); + } return; #if DL_CURRENT_VERSION >= 2 @@ -1000,18 +1219,18 @@ dlpi_request(q, mp, us) #endif case DL_CONNECT_REQ: case DL_TOKEN_REQ: - dlpi_error(q, d->dl_primitive, DL_NOTSUPPORTED, 0); + dlpi_error(q, us, d->dl_primitive, DL_NOTSUPPORTED, 0); break; case DL_CONNECT_RES: case DL_DISCONNECT_REQ: case DL_RESET_REQ: case DL_RESET_RES: - dlpi_error(q, d->dl_primitive, DL_OUTSTATE, 0); + dlpi_error(q, us, d->dl_primitive, DL_OUTSTATE, 0); break; case DL_UDQOS_REQ: - dlpi_error(q, d->dl_primitive, DL_BADQOSTYPE, 0); + dlpi_error(q, us, d->dl_primitive, DL_BADQOSTYPE, 0); break; #if DL_CURRENT_VERSION >= 2 @@ -1024,20 +1243,23 @@ dlpi_request(q, mp, us) cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive); /* fall through */ badprim: - dlpi_error(q, d->dl_primitive, DL_BADPRIM, 0); + dlpi_error(q, us, d->dl_primitive, DL_BADPRIM, 0); break; } freemsg(mp); } static void -dlpi_error(q, prim, err, uerr) +dlpi_error(q, us, prim, err, uerr) queue_t *q; + upperstr_t *us; int prim, err, uerr; { mblk_t *reply; dl_error_ack_t *errp; + if (us->flags & US_DBGLOG) + DPRINT3("ppp/%d: dlpi error, prim=%x, err=%x\n", us->mn, prim, err); reply = allocb(sizeof(dl_error_ack_t), BPRI_HI); if (reply == 0) return; /* XXX should do bufcall */ @@ -1071,6 +1293,47 @@ dlpi_ok(q, prim) } #endif /* NO_DLPI */ +static int +pass_packet(us, mp, outbound) + upperstr_t *us; + mblk_t *mp; + int outbound; +{ + int pass; + upperstr_t *ppa; + + if ((ppa = us->ppa) == 0) { + freemsg(mp); + return 0; + } + +#ifdef FILTER_PACKETS + pass = ip_hard_filter(us, mp, outbound); +#else + /* + * Here is where we might, in future, decide whether to pass + * or drop the packet, and whether it counts as link activity. + */ + pass = 1; +#endif /* FILTER_PACKETS */ + + if (pass < 0) { + /* pass only if link already up, and don't update time */ + if (ppa->lowerq == 0) { + freemsg(mp); + return 0; + } + pass = 1; + } else if (pass) { + if (outbound) + ppa->last_sent = time; + else + ppa->last_recv = time; + } + + return pass; +} + static int send_data(mp, us) mblk_t *mp; @@ -1079,21 +1342,30 @@ send_data(mp, us) queue_t *q; upperstr_t *ppa; - if (us->flags & US_BLOCKED || us->npmode == NPMODE_QUEUE) + if ((us->flags & US_BLOCKED) || us->npmode == NPMODE_QUEUE) return 0; ppa = us->ppa; if (ppa == 0 || us->npmode == NPMODE_DROP || us->npmode == NPMODE_ERROR) { + if (us->flags & US_DBGLOG) + DPRINT2("ppp/%d: dropping pkt (npmode=%d)\n", us->mn, us->npmode); freemsg(mp); return 1; } if ((q = ppa->lowerq) == 0) { /* try to send it up the control stream */ - if (canputnext(ppa->q)) { - putnext(ppa->q, mp); + if (bcanputnext(ppa->q, mp->b_band)) { + /* + * The message seems to get corrupted for some reason if + * we just send the message up as it is, so we send a copy. + */ + mblk_t *np = copymsg(mp); + freemsg(mp); + if (np != 0) + putnext(ppa->q, np); return 1; } } else { - if (canputnext(ppa->lowerq)) { + if (bcanputnext(ppa->lowerq, mp->b_band)) { /* * The lower write queue's put procedure just updates counters * and does a putnext. We call it so that on SMP systems, we @@ -1136,7 +1408,7 @@ new_ppa(q, mp) us->flags |= US_CONTROL; us->npmode = NPMODE_PASS; - us->mtu = PPP_MRU; + us->mtu = PPP_MTU; us->mru = PPP_MRU; #ifdef SOL2 @@ -1313,7 +1585,7 @@ pppursrv(q) #ifndef NO_DLPI proto = PPP_PROTOCOL(mp->b_rptr); mp->b_rptr += PPP_HDRLEN; - hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong), + hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint), BPRI_MED); if (hdr == 0) { /* XXX should put it back and use bufcall */ @@ -1322,21 +1594,21 @@ pppursrv(q) } 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(ulong); + 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(ulong); + ud->dl_dest_addr_length = sizeof(uint); ud->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t); - ud->dl_src_addr_length = sizeof(ulong); - ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(ulong); + 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) */ - ((ulong *)(ud + 1))[0] = us->req_sap; /* dest SAP */ - ((ulong *)(ud + 1))[1] = us->req_sap; /* src SAP */ + ((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); @@ -1429,6 +1701,22 @@ ppplrput(q, mp) putnext(us->q, mp); break; + case M_HANGUP: + /* + * The serial device has hung up. We don't want to send + * the M_HANGUP message up to pppd because that will stop + * us from using the control stream any more. Instead we + * send a zero-length message as an end-of-file indication. + */ + freemsg(mp); + mp = allocb(1, BPRI_HI); + if (mp == 0) { + DPRINT1("ppp/%d: couldn't allocate eof message!\n", ppa->mn); + break; + } + putnext(ppa->q, mp); + break; + default: if (mp->b_datap->db_type == M_DATA) { len = msgdsize(mp); @@ -1450,11 +1738,12 @@ ppplrput(q, mp) * A data packet for some network protocol. * Queue it on the upper stream for that protocol. */ + if (!pass_packet(us, mp, 0)) + break; if (canput(us->q)) putq(us->q, mp); else putq(q, mp); - ppa->last_recv = time; break; } } @@ -1573,3 +1862,113 @@ debug_dump(q, mp) } } } + +#ifdef FILTER_PACKETS +#include +#include +#include +#include + +#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 int +ip_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 */ +