home *** CD-ROM | disk | FTP | other *** search
- /*
- * dp_if.c - Streams PPP top level module handles if_ and packetizing
- * PPP packets.
- * Copyright (C) 1990 Brad K. Clements, All Rights Reserved
- */
- /*
- * Copyright (c) 1992 Purdue University
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Purdue University. The name of the University may not be used
- * to endorse or promote products derived * from this software without
- * specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Note: this copyright applies to portions of this software developed
- * at Purdue beyond the software covered by the original copyright.
- */
-
- /*
- * This file contains 3 basic parts, which are somewhat mixed together.
- *
- * "dpif" streams module
- * This can be pushed on a stream to connect it to a "dp" network
- * interface. It routes PPP packets through the stream to the user
- * process and network packets (IP) through the "dp" network interface.
- * "dp" network interface
- * This is a network interface (like an ethernet driver), that implements
- * a Point to Point TCP/IP network interface. It communicates with
- * the "dpif" streams module for input and output on the serial
- * stream and passes packets back and forth to the kernel networking
- * modules.
- * "pppdial" streams device
- * This is a streams device that can be opened by a user process.
- * Messages are sent to the user process through this device when
- * the "dp" network interface needs to establish a connection to
- * send packets on a particular network interface.
- */
- #define VJC 1
- #include <sys/types.h>
-
- #ifndef LOADABLE
- #include "dp.h"
- #endif
- #if NDP > 0
-
- #define STREAMS 1
-
- #define PPP_STATS 1
- #define PPP_SNIT 1 /* pass packets to Streams Network Interface Tap */
-
- #define DEBUGS 1
-
- #include <sys/param.h>
- #include <sys/stream.h>
- #include <sys/stropts.h>
-
- #include <sys/user.h>
- #include <sys/systm.h>
- #include <sys/mbuf.h>
- #include <sys/socket.h>
- #include <sys/errno.h>
- #include <sys/ioctl.h>
- #include <sys/file.h>
- #include <sys/uio.h>
- #include <sys/signal.h>
- #include <net/if.h>
- #include <net/netisr.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/in_var.h>
- #include <netinet/ip.h>
- #ifdef PPP_STATS
- #ifdef LOADABLE
- #include "slip_var.h"
- #else
- #include <sys/slip_var.h>
- #endif
- #define INCR(comp) ++p->pii_stats.comp
- #else
- #define INCR(comp)
- #endif
-
- #ifdef VJC
- #ifdef LOADABLE
- #include "slcompress.h"
- #else
- #include <sys/slcompress.h>
- #endif
- #endif
- #ifdef LOADABLE
- #include "if_ppp.h"
- #include "dp_str.h"
- #else
- #include <sys/if_ppp.h>
- #include <sys/dp_str.h>
- #endif
- #include <netinet/tcp.h>
- #ifdef DEBUGS
- #include <sys/syslog.h>
- static char *dus_str[] = {
- "ACTIVE",
- "ACTIVEC",
- "ACTIVEU",
- "WAITING",
- "FAILCALL",
- "DISCON",
- "DOWN",
- };
- static char *cstat_str[] = {
- "FAILURE",
- "SUCCESS",
- "IN_PROGRESS",
- "NO_MODEM"
- };
- #define DLOG(s,a) if (dp_if_debug) log(LOG_INFO, s, a)
- #define DLOG2(s,a1,a2) if (dp_if_debug) log(LOG_INFO, s, a1, a2)
- #define DLOG3(s,a,b,c) if (dp_if_debug) log(LOG_INFO, s, a, b, c)
- #define DLOG5(s,a,b,c,d,e) if (dp_if_debug) log(LOG_INFO, s, a, b, c, d, e)
- #define DLOGFLAGS(s) DLOG2(s, p->pii_ifnet.if_flags, p->pii_flags)
- #define DLOGSTATE(s) if (dp_if_debug) log(LOG_INFO, s, dus_str[p->pii_dustate])
- int dp_if_debug=0;
- int dp_ftimo_debug=0;
- #define static
- #define DLOG_ACTIVE(event) if (dp_if_debug || dp_active_debug) log(LOG_INFO, "%c %s %d %d/%d", xmit ? 'T' : 'R', (event), act->da_nactive, act->da_misses, act->da_lookups)
- int dp_active_debug = 0;
- #else
- #define DLOG(s,a) {}
- #define DLOG2(s,a1,a2) {}
- #define DLOG3(s,a,b,c) {}
- #define DLOG5(s,a,b,c,d,e) {}
- #define DLOGFLAGS(s) {}
- #define DLOGSTATE(s) {}
- #define DLOG_ACTIVE(s) {}
- #endif
-
- #ifdef PPP_SNIT
- #include <net/nit_if.h>
- #include <netinet/if_ether.h>
- /* Use a fake link level header to make etherfind and tcpdump happy. */
- static struct ether_header header = {{1}, {2}, ETHERTYPE_IP};
- static struct nit_if nif = {(caddr_t)&header, sizeof(header), 0, 0};
- #endif
-
- #ifdef LOADABLE
- #include <sys/conf.h>
- #include <sys/buf.h>
- #include <sundev/mbvar.h>
- #include <sun/autoconf.h>
- #include <sun/vddrv.h>
- #endif
-
- static int dp_if_open(), dp_if_close(),
- dp_if_rput(), dp_if_wput(),
- dp_if_wsrv(), dp_if_rsrv();
-
- static struct module_info dp_minfo ={
- 0xbad,"dpif",0, INFPSZ, 16384, 4096
- };
-
- static struct qinit dpr_init = {
- dp_if_rput, dp_if_rsrv, dp_if_open, dp_if_close, NULL, &dp_minfo, NULL
- };
- static struct qinit dpw_init = {
- dp_if_wput, dp_if_wsrv, dp_if_open, dp_if_close, NULL, &dp_minfo, NULL
- };
- struct streamtab dp_ifinfo = {
- &dpr_init, &dpw_init, NULL, NULL, NULL
- };
-
- typedef struct dp_if_info PII;
-
- PII dupii[NDP];
-
- static int dp_start(), dp_timer(), dp_ioctl(), dp_output();
- static void dp_flush();
-
- static int dp_deftimo[PII_DP_NSTATES] = {
- DP_DEF_ATIMEO, /* Activity Timeout */
- DP_DEF_CTIMEO, /* Last TCP Close Timeout */
- DP_DEF_UTIMEO, /* Non-TCP traffic timeout */
- DP_DEF_WTIMEO, /* Call Wait Timeout */
- DP_DEF_FTIMEO, /* Failed Call Timeout */
- DP_NO_TIMEOUT, /* No Disconnect Timeout */
- DP_NO_TIMEOUT /* No Down Timeout */
- };
-
- static void dp_active_init(),
- dp_active_tinit(),
- dp_active();
-
- static int
- dp_attach(unit)
- int unit;
- {
- register PII *p = &dupii[unit];
- register struct ifnet *ifp = &dupii[unit].pii_ifnet;
-
- ifp->if_name = "dp";
- ifp->if_mtu = PPP_MTU;
- ifp->if_flags = IFF_POINTOPOINT;
- ifp->if_unit = unit;
- ifp->if_ioctl = dp_ioctl;
- ifp->if_output = dp_output;
- ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
- ifp->if_watchdog = dp_timer;
- ifp->if_timer = 0;
- if_attach(ifp);
- p->pii_flags |= PII_FLAGS_ATTACHED;
- }
-
- static void
- dp_init(unit)
- int unit;
- {
- register PII *p = &dupii[unit];
- register struct ifnet *ifp = &p->pii_ifnet;
- register int i;
-
- /*
- * Initialize the dialup stuff..
- */
-
- if (!(ifp->if_flags & IFF_UP))
- return;
- if (!(p->pii_flags & PII_FLAGS_INITTED)) {
- p->pii_flags |= PII_FLAGS_INITTED;
- for (i = 0 ; i < PII_DP_NSTATES ; i++)
- p->pii_timo[i] = dp_deftimo[i];
- dp_state(p, PII_DPS_DISCON);
- DLOG3("dp_init: timeouts %d %d %d\n", p->pii_timo[0] * DP_HZ,
- p->pii_timo[1] * DP_HZ, p->pii_timo[2] * DP_HZ);
- }
-
- ifp->if_flags |= IFF_UP|IFF_RUNNING;
- }
-
- static int
- dp_if_open(q, dev, flag, sflag)
- queue_t *q;
- dev_t dev;
- int flag,
- sflag;
- {
- if (!suser()) {
- u.u_error = EPERM;
- return OPENFAIL;
- }
- return 0;
- }
-
- static int
- dp_if_unit(q, unit)
- queue_t *q;
- int unit;
- {
- register PII *p;
- int s;
-
- DLOG("dp_if_unit: enter %d\n", unit);
- if (unit < 0 || unit >= NDP)
- return EINVAL;
- if (q->q_ptr)
- return EBUSY;
-
- s = splstr();
- p = &dupii[unit];
-
- if (p->pii_writeq) {
- splx(s);
- return EBUSY;
- }
- #ifdef VJC
- #ifdef PPP_STATS
- bzero(&p->pii_stats,sizeof(p->pii_stats));
- #endif
- sl_compress_init(&p->pii_sc_comp);
- #endif
- dp_active_init(&p->pii_active);
- if (!(p->pii_flags & PII_FLAGS_ATTACHED))
- dp_attach(unit); /* attach it */
- p->pii_writeq = q;
- RD(q)->q_ptr = q->q_ptr = (caddr_t) p; /* set write Q and read Q to point here */
- p->pii_flags |= PII_FLAGS_INUSE|PII_FLAGS_ATTACHED;
- DLOG("dp_if_unit: exit %d\n", unit);
- splx(s);
- return 0;
- }
-
- static int
- dp_if_close(q)
- queue_t *q; /* queue info */
- {
- PII *p = (PII *) q->q_ptr;
- int s;
-
- s = splimp();
- dp_flush(p, q);
- if (p) {
- p->pii_flags &= ~PII_FLAGS_INUSE;
- switch (p->pii_dustate) {
- case PII_DPS_DOWN:
- break;
- case PII_DPS_DISCON:
- case PII_DPS_WAITING:
- case PII_DPS_ACTIVE:
- case PII_DPS_FAILCALL:
- dp_state(p, PII_DPS_DISCON);
- break;
- default:
- DLOG("dp_if_close: unknown state %d\n", p->pii_dustate);
- break;
- }
- p->pii_writeq = (queue_t *)0;
- q->q_ptr = (char *)0;
- DLOG("dp_if%d: closed\n", (p-dupii)/sizeof(PII));
- }
- else
- DLOG("dp_if: closed\n", p);
- splx(s);
- return(0); /* no work to be done */
- }
-
- static void
- dp_flush(p, q)
- register PII *p;
- register queue_t *q;
- {
- if (p)
- if_qflush(&p->pii_ifnet.if_snd);
- if (q) {
- flushq(q, FLUSHALL);
- flushq(OTHERQ(q), FLUSHALL);
- }
- }
-
-
- static int
- dp_ioc_sint(mp, i, valp)
- register mblk_t *mp;
- register struct iocblk *i;
- int *valp;
- {
- if (i->ioc_count != sizeof(int)) {
- i->ioc_error = EINVAL;
- return -1;
- }
- *valp = *(int *)mp->b_cont->b_rptr;
- return 0;
- }
-
- /*
- *
- * dp_callstat() provides for the following state transitions..
- *
- * State Status New State
- * FAILCALL IN_PROGRESS WAITING (dplogin starting..)
- * DISCON IN_PROGRESS WAITING (dplogin starting..)
- * WAITING FAILURE FAILCALL (couldn't complete call)
- * WAITING NO_MODEM DISCON (no modems, immediate retry ok)
- * WAITING SUCCESS ACTIVE (start packets flowing)
- */
-
- static int
- dp_callstat(p, stat)
- register PII *p;
- char stat;
- {
- #ifdef DEBUGS
- if (dp_if_debug) {
- if (DP_VALID_STATUS(stat))
- log(LOG_INFO, "dp_callstat: state %s stat %s\n",
- dus_str[p->pii_dustate], cstat_str[stat]);
- else
- log(LOG_INFO, "dp_callstat: state %s stat %d\n",
- dus_str[p->pii_dustate], stat);
- }
- #endif
- switch (p->pii_dustate) {
- case PII_DPS_DOWN:
- case PII_DPS_ACTIVE:
- break;
-
- /*
- * Not connected, so transition to WAITING if dplogin is starting up..
- */
- case PII_DPS_FAILCALL:
- case PII_DPS_DISCON:
- switch (stat) {
- case DP_IN_PROGRESS:
- dp_state(p, PII_DPS_WAITING);
- break;
- case DP_SUCCESS:
- dp_state(p, PII_DPS_ACTIVE);
- break;
- }
-
- /*
- * Waiting for a connection to be established.
- * Respond properly to the result returned.
- */
- case PII_DPS_WAITING:
- switch (stat) {
- case DP_SUCCESS:
- dp_state(p, PII_DPS_ACTIVE);
- (void)dp_start(p);
- break;
- case DP_FAILURE:
- dp_state(p, PII_DPS_FAILCALL);
- dp_flush(p, p->pii_writeq);
- break;
- case DP_NO_MODEM:
- dp_state(p, PII_DPS_DISCON);
- dp_flush(p, p->pii_writeq);
- }
- break;
- }
- }
-
- static int
- dp_if_wput(q, mp)
- queue_t *q;
- register mblk_t *mp;
- {
-
- register struct iocblk *i;
- register PII *p;
- int x;
-
- switch (mp->b_datap->db_type) {
- case M_FLUSH:
- if (*mp->b_rptr & FLUSHW)
- flushq(q, FLUSHDATA);
- putnext(q, mp); /* send it along too */
- break;
-
- case M_DATA:
- if (!q->q_ptr) {
- mp->b_datap->db_type = M_ERROR;
- mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
- *mp->b_wptr++ = ENXIO;
- qreply(q, mp);
- }
- else
- putq(q, mp); /* queue it for my service routine */
- break;
-
- case M_IOCTL:
- i = (struct iocblk *) mp->b_rptr;
- p = (PII *) q->q_ptr;
- if (!p && i->ioc_cmd != SIOCSIFUNIT)
- goto passalong;
-
- switch (i->ioc_cmd) {
- case SIOCSIFCOMPAC: /* enable or disable AC compression */
- if (i->ioc_count != sizeof(u_char))
- goto passalong;
- DLOG("dp_if: SIFCOMPAC %d\n", *(u_char *) mp->b_cont->b_rptr);
- if ( *(u_char *) mp->b_cont->b_rptr)
- p->pii_flags |= PII_FLAGS_COMPAC;
- else
- p->pii_flags &= ~PII_FLAGS_COMPAC;
- goto passalong;
-
- case SIOCSIFCOMPPROT: /* enable or disable PROT compression */
- DLOG("dp_if: SIFCOMPPROT %d\n", *(u_char *) mp->b_cont->b_rptr);
- if (i->ioc_count != sizeof(u_char))
- goto passalong;
- if ( *(u_char *) mp->b_cont->b_rptr)
- p->pii_flags |= PII_FLAGS_COMPPROT;
- else
- p->pii_flags &= ~PII_FLAGS_COMPPROT;
- goto passalong;
-
- case SIOCSIFVJCOMP: /* enable or disable VJ compression */
- #ifdef VJC
- if (i->ioc_count != sizeof(u_char))
- goto passalong;
- DLOG("dp_if: SIFVJCOMP %d\n", *(u_char *) mp->b_cont->b_rptr);
- if ( *(u_char *) mp->b_cont->b_rptr)
- p->pii_flags |= PII_FLAGS_VJC_ON;
- else
- p->pii_flags &= ~PII_FLAGS_VJC_ON;
- mp->b_datap->db_type = M_IOCACK;
- #else
- mp->b_datap->db_type = M_IOCNAK;
- i->ioc_error = EINVAL;
- i->ioc_count = 0;
- #endif
- qreply(q, mp);
- break;
-
- /*
- * The remaining ioctl's support the options for dialup.
- */
- case SIOCSIFUNIT:
- DLOG2("dp_if: SIFSIFUNIT %d p %x\n",
- *(int *)mp->b_cont->b_rptr, p);
- if (i->ioc_count != sizeof(int)) {
- i->ioc_error = EINVAL;
- goto iocnak;
- }
- if (x = dp_if_unit(q, *(int *)mp->b_cont->b_rptr)) {
- i->ioc_error = x;
- goto iocnak;
- }
- else {
- p = (PII *) q->q_ptr;
- goto iocack;
- }
-
- case SIOCGIFUNIT: /* get unit number */
- case SIOCGETU:
- DLOG("dp_if: SIFGIFUNIT %d\n", p->pii_ifnet.if_unit);
- if (mp->b_cont = allocb(sizeof(int), BPRI_MED)) {
- *(int *)mp->b_cont->b_wptr = p->pii_ifnet.if_unit;
- mp->b_cont->b_wptr += i->ioc_count = sizeof(int);
- mp->b_datap->db_type = M_IOCACK;
- }
- else {
- i->ioc_error = ENOSR;
- i->ioc_count = 0;
- mp->b_datap->db_type = M_IOCNAK;
- }
- qreply(q, mp);
- break;
-
- case SIOCCALLSTAT: /* Report Call Status */
- DLOG("dp_if: SIFCALLSTAT %d\n", *(char *)mp->b_cont->b_rptr);
- if (i->ioc_count != sizeof(char)) {
- i->ioc_error = EINVAL;
- iocnak:
- i->ioc_count = 0;
- mp->b_datap->db_type = M_IOCNAK;
- qreply(q, mp);
- break;
- }
- x = splimp();
- dp_callstat(p, (int)*mp->b_cont->b_rptr);
- splx(x);
- iocack:
- mp->b_datap->db_type = M_IOCACK;
- qreply(q, mp);
- break;
-
- case SIOCSDPTIMEO: /* Set Timeouts */
- if (i->ioc_count != DP_NTIMEOUTS * sizeof(u_long) * DP_NTIMEOUTS) {
- i->ioc_error = EINVAL;
- goto iocnak;
- }
- dp_settimos(p, (u_long *)mp->b_cont->b_rptr, 0, DP_NTIMEOUTS);
- break;
- case SIOCGDPTIMEO: /* Get Timeouts */
- if (mp->b_cont = allocb(DP_NTIMEOUTS * sizeof(u_long), BPRI_MED)) {
- dp_gettimos(p, (u_long *)mp->b_cont->b_wptr, 0, DP_NTIMEOUTS);
- mp->b_cont->b_wptr += i->ioc_count
- = DP_NTIMEOUTS * sizeof(u_long);
- mp->b_datap->db_type = M_IOCACK;
- }
- else {
- i->ioc_error = ENOSR;
- i->ioc_count = 0;
- mp->b_datap->db_type = M_IOCNAK;
- }
- qreply(q, mp);
- break;
-
- default: /* unknown IOCTL call */
- passalong:
- putnext(q,mp); /* pass it along */
- }
- DLOG("dp_if_wput: Pii->flags %x\n", p->pii_flags);
- break;
- default:
- putnext(q,mp); /* don't know what to do with this, so send it along*/
- }
- }
-
- static int
- dp_if_wsrv(q)
- queue_t *q;
- {
- register mblk_t *mp;
- register PII *p;
-
- p = (PII *) q->q_ptr;
-
- while ((mp = getq(q)) != NULL) {
- /*
- * We can only get M_DATA types into our Queue,
- * due to our Put function
- */
- if (!canput(q->q_next)) {
- putbq(q, mp);
- return;
- }
- putnext(q, mp); /* just pass it along, nothing to do in this direction */
- }
- }
-
- static int
- dp_if_rput(q, mp)
- queue_t *q;
- register mblk_t *mp;
- {
- register u_char *c;
- register PII *p;
-
- switch (mp->b_datap->db_type) {
- case M_FLUSH:
- if (*mp->b_rptr & FLUSHR)
- flushq(q, FLUSHDATA);
- putnext(q, mp); /* send it along too */
- break;
-
- case M_DATA:
- putq(q, mp); /* queue it for my service routine */
- break;
-
- case M_CTL: /* could be a message from below */
- p = (PII *) q->q_ptr;
- c = (u_char *) mp->b_rptr;
- switch (*c) {
- case IF_INPUT_ERROR:
- p->pii_ifnet.if_ierrors++;
- INCR(sl_ierrors);
- DLOG("dp_if: input error inc to %d\n", p->pii_ifnet.if_ierrors);
- break;
- case IF_OUTPUT_ERROR:
- p->pii_ifnet.if_oerrors++;
- INCR(sl_oerrors);
- DLOG("dp_if: output error inc to %d\n", p->pii_ifnet.if_oerrors);
- break;
- default:
- break;
- }
- freemsg(mp);
- /* putnext(q, mp); */
- break;
- default:
- putnext(q,mp); /* don't know what to do with this, so send it along*/
- }
- }
-
- static int
- dp_if_rsrv(q)
- queue_t *q;
- {
- register mblk_t *mp, *m0;
- #ifdef VJC
- register mblk_t *mvjc;
- unsigned char *cp;
-
- #endif
- register PII *p;
- struct ifnet **ifp;
- struct ppp_header *ph;
- struct mbuf *mb1, *mb2,*mbtail;
- int len,xlen,count,s;
- u_char *rptr;
-
- p = (PII *) q->q_ptr;
-
- while ((mp = getq(q)) != NULL) {
- /* we can only get M_DATA types into our Queue, due to our Put function */
- m0 = mp; /* remember first message block */
- ph = (struct ppp_header *) mp->b_rptr;
- /* assume ppp_header is completely in first block */
- if (mp->b_wptr - mp->b_rptr < sizeof(struct ppp_header)) {
- freemsg(mp);
- p->pii_ifnet.if_ierrors++;
- continue;
- }
- #ifdef VJC
- switch (ntohs(ph->ph_protocol)) {
- case PPP_IP:
- break;
- case PPP_VJC_COMP:
- if (p->pii_flags & PII_FLAGS_VJC_ON) {
- for (xlen=0, mvjc = mp ; mvjc ; mvjc = mvjc->b_cont)
- xlen += (mvjc->b_wptr - mvjc->b_rptr);
- xlen -= sizeof(struct ppp_header);
- if (!(mvjc = allocb(128, BPRI_MED))) {
- /* get a 128 byte buffer for IP header*/
- putbq(q,mp);
- qenable(q);
- return;
- }
- mvjc->b_wptr += 128;
- linkb(mvjc,mp);
- if (!pullupmsg(mvjc,-1)) {
- /* string em all together. ugh what a waste */
- freemsg(mvjc);
- continue;
- }
- cp = mvjc->b_rptr + 128 + sizeof(struct ppp_header);
- m0 = mp = mvjc;
- xlen = sl_uncompress_tcp(&cp,xlen, TYPE_COMPRESSED_TCP, &p->pii_sc_comp);
- if (!xlen) {
- DLOG("dp: sl_uncompress failed on type Compressed",0);
- goto reject;
- }
- mp->b_rptr = cp - sizeof(struct ppp_header);
- ((struct ppp_header *) mp->b_rptr)->ph_protocol = htons(PPP_IP);
- break;
- }
-
- case PPP_VJC_UNCOMP:
- if (p->pii_flags & PII_FLAGS_VJC_ON) {
- cp = (unsigned char *) mp->b_rptr + sizeof(struct ppp_header);
- if (sl_uncompress_tcp(&cp, 1, TYPE_UNCOMPRESSED_TCP, &p->pii_sc_comp)) {
- ((struct ppp_header *) mp->b_rptr)->ph_protocol = htons(PPP_IP);
- break;
- }
- DLOG("dp: sl_uncompress failed on type Uncompresed\n",0);
- reject:
- freemsg(mp);
- continue;
- }
- default:
- #endif
- #ifndef VJC
- if (ntohs(ph->ph_protocol) != PPP_IP) {
- #endif
- #ifdef DEBUGS
- if (dp_if_debug) {
- switch (ntohs(ph->ph_protocol) & 0xf000) {
- case PPP_LCP:
- DLOG("dp: LCP packet 0x%x\n", ntohs(ph->ph_protocol));
- break;
- case PPP_NCP:
- DLOG("dp: NCP packet 0x%x\n", ntohs(ph->ph_protocol));
- break;
- default:
- DLOG("dp: unknown protocol 0x%x\n",
- ntohs(ph->ph_protocol));
- }
- }
- #endif
- INCR(sl_ipackets);
- if (!canput(q->q_next)) {
- putbq(q, mp);
- return;
- }
- putnext(q,mp);
- p->pii_ifnet.if_ipackets++;
- continue;
- #ifndef VJC
- }
- #endif
- }
- len = 0;
- mb1 = NULL;
- xlen = mp->b_wptr - (rptr = mp->b_rptr);
- while (mp) {
- if (len < 1) {
- MGET(mb2, M_DONTWAIT, MT_DATA);
- if (!mb2) {
- p->pii_ifnet.if_ierrors++;
- putbq(q,m0);
- qenable(q);
- if (mb1)
- m_freem(mb1); /* discard what we've used already */
- return;
- } /* if we couldn't get a buffer, put back the message and try later */
- len = MLEN;
- mb2->m_len = 0;
- if (mb1) {
- mbtail->m_next = mb2;
- mbtail = mb2;
- }
- else
- mbtail = mb1 = mb2;
- }
- count = MIN(xlen, len);
- bcopy((char *) rptr, mtod(mb2, char *) + mb2->m_len, count);
- #ifdef PPP_STATS
- p->pii_stats.sl_ibytes += count;
- #endif
- rptr += count;
- len -= count;
- xlen -= count;
- mb2->m_len += count;
- if (!xlen) { /* move to the next mblk */
- mp = mp->b_cont;
- if (mp)
- xlen = mp->b_wptr - (rptr = mp->b_rptr);
- }
- }
- #define HADJ (sizeof(struct ppp_header) - sizeof(struct ifnet *))
- /* note, HADJ >= 0 is assumed */
-
- ifp = (struct ifnet **) (mtod(mb1, u_char *) + HADJ);
- *ifp = &p->pii_ifnet; /* stick ifnet * in front of packet */
- mb1->m_off += HADJ;
- mb1->m_len -= HADJ;
- freemsg(m0);
- #ifdef PPP_SNIT
- if (p->pii_ifnet.if_flags & IFF_PROMISC) {
- struct mbuf *m = mb1;
-
- len = 0;
- do {
- len += m->m_len;
- } while (m = m->m_next);
- nif.nif_bodylen = len - sizeof(struct ifnet *);
- mb1->m_off += sizeof(struct ifnet *);
- snit_intr(&p->pii_ifnet, mb1, &nif);
- mb1->m_off -= sizeof(struct ifnet *);
- }
- #endif
- p->pii_ifnet.if_ipackets++;
- INCR(sl_ipackets);
- #define IPADJ sizeof(struct ppp_header)
- dp_active(p, (struct ip *)(mtod(mb1, u_char *) + IPADJ),
- mb1->m_len - IPADJ, 0);
- s = splimp();
- if (IF_QFULL(&ipintrq)) {
- IF_DROP(&ipintrq);
- p->pii_ifnet.if_ierrors++;
- m_freem(mb1);
- }
- else {
- IF_ENQUEUE(&ipintrq, mb1);
- schednetisr(NETISR_IP);
- }
- splx(s);
- } /* end while */
-
- }
-
- /* ifp output procedure */
- int
- dp_output(ifp, m0, dst)
- struct ifnet *ifp;
- struct mbuf *m0;
- struct sockaddr *dst;
- {
- register PII *p = &dupii[ifp->if_unit];
- struct mbuf *m;
- int error, s;
- u_short protocol;
-
- DLOG2("dp_output: state %s flags %x\n", dus_str[p->pii_dustate], p->pii_flags);
-
- error = 0;
- if (!(ifp->if_flags & IFF_RUNNING)) {
- error = ENETDOWN;
- goto getout;
- }
-
- switch (p->pii_dustate) {
- case PII_DPS_ACTIVE:
- /*
- * The easy case..
- * The line is active and we are set..
- */
- break;
-
- case PII_DPS_DOWN:
- case PII_DPS_FAILCALL:
- /*
- * If the net is marked down or we have recently failed in calling,
- * might as well give up now.
- */
- DLOGSTATE("dp_output: NETDOWN %s\n");
- error = ENETDOWN;
- goto getout;
-
- case PII_DPS_WAITING:
- /*
- * If we are waiting on a call to go through, queue this packet
- * and don't signal any error.
- */
- DLOGFLAGS("dp_output: DPS_WAITING %x %x\n");
- goto qpacket;
-
- case PII_DPS_DISCON:
- /*
- * If not already talking on the line,
- * try to initiate a call.
- */
- switch (dst->sa_family) {
- #ifdef INET
- case AF_INET:
- if (duipreq(m0, dst, ifp)) {
- DLOGFLAGS("dp_output: duipreq failed %x %x\n");
- error = ENETDOWN;
- goto getout;
- }
- break;
- #endif
- default:
- /*
- * Punt for now.
- */
- DLOGFLAGS("dp_output: DISCON bad family %x %x\n");
- error = ENETDOWN;
- goto getout;
- }
- dp_state(p, PII_DPS_WAITING);
- DLOGFLAGS("dp_output: duipreq in progress %x %x\n");
- goto qpacket;
-
- default:
- DLOG("dp_output: unknown state %d\n", p->pii_dustate);
- break;
- }
-
- qpacket:
- switch (dst->sa_family) {
- #ifdef INET
- case AF_INET:
- #ifdef PPP_SNIT
- if (ifp->if_flags & IFF_PROMISC) {
- struct mbuf *m = m0;
- int len = 0;
- do {
- len += m->m_len;
- } while (m = m->m_next);
- nif.nif_bodylen = len;
- snit_intr(ifp, m0, &nif);
- }
- #endif
- protocol = PPP_IP;
- break;
- #endif
- #ifdef NS
- case AF_NS:
- protocol = PPP_XNS;
- break;
- #endif
- default:
- printf("dp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
- error = EAFNOSUPPORT;
- goto getout;
- }
- /*
- * Prepend the protocol to this packet.
- */
- if (m0->m_off > MMAXOFF || MMINOFF + sizeof(protocol) > m0->m_off) {
- m = m_get(M_DONTWAIT, MT_HEADER);
- if (m == 0) {
- error = ENOBUFS;
- goto getout;
- }
- m->m_next = m0;
- m->m_len = sizeof(protocol);
- m0 = m;
- }
- else {
- m0->m_off -= sizeof(protocol);
- m0->m_len += sizeof(protocol);
- }
- bcopy((caddr_t)&protocol, mtod(m0, caddr_t), sizeof(protocol));
-
- s = splimp();
- if (IF_QFULL(&ifp->if_snd))
- IF_DROP(&ifp->if_snd);
- IF_ENQUEUE(&ifp->if_snd, m0);
- error = dp_start(p);
- splx(s);
- if (error) {
- INCR(sl_oerrors);
- p->pii_ifnet.if_oerrors++;
- }
- return(error); /* gads, streams are great */
- getout:
- if (m0)
- m_freem(m0);
- if (error) {
- INCR(sl_oerrors);
- p->pii_ifnet.if_oerrors++;
- }
- return(error); /* gads, streams are great */
- }
-
- static int
- dp_start(p)
- register PII *p;
- {
- struct mbuf *m0, *m1;
- int len;
- u_short protocol;
- mblk_t *mp;
- int s;
- #ifdef VJC
- u_char type;
- #endif
-
- while (p->pii_ifnet.if_snd.ifq_head && p->pii_writeq &&
- (p->pii_dustate == PII_DPS_ACTIVE)) {
- IF_DEQUEUE(&p->pii_ifnet.if_snd, m0);
- protocol = *mtod(m0, u_short *);
- bcopy(mtod(m0, caddr_t), (caddr_t)&protocol, sizeof(protocol));
- m0->m_off += sizeof(protocol);
- m0->m_len -= sizeof(protocol);
- if (m0->m_len == 0)
- m0 = m_free(m0);
- #ifdef VJC
- if ((protocol == PPP_IP) && (p->pii_flags & PII_FLAGS_VJC_ON)) {
- register struct ip *ip;
- if ((m0->m_off > MMAXOFF || m0->m_len < sizeof(struct ip)) &&
- (m0 = m_pullup(m0, sizeof(struct ip))) == 0) {
- INCR(sl_oerrors);
- p->pii_ifnet.if_oerrors++;
- return ENOBUFS;
- }
-
- ip = mtod(m0, struct ip *);
- dp_active(p, ip, m0->m_len, 1);
- if (ip->ip_p == IPPROTO_TCP) {
- type = sl_compress_tcp(m0, ip, &p->pii_sc_comp, 1);
- switch (type) {
- case TYPE_UNCOMPRESSED_TCP:
- protocol = PPP_VJC_UNCOMP;
- break;
- case TYPE_COMPRESSED_TCP:
- protocol = PPP_VJC_COMP;
- break;
- }
- }
- }
- #endif
- len = 0;
- for (m1 = m0; m1; m1 = m1->m_next)
- len += m1->m_len;
- if (!(p->pii_flags & PII_FLAGS_COMPAC))
- len += 2; /* if we are not compac, then need 2 extra bytes */
- if (!(p->pii_flags & PII_FLAGS_COMPPROT))
- len++;
- len++;
- /*
- * We never need to check the actual protocol, since
- * its always either PPP_IP, PPP_VJC_*, or PPP_XNS
- */
- if (!(mp = allocb(len, BPRI_LO))) {
- INCR(sl_oerrors);
- p->pii_ifnet.if_oerrors++;
- m_freem(m0);
- return ENOBUFS;
- }
- #ifdef PPP_STATS
- p->pii_stats.sl_obytes += len;
- #endif
- if (!(p->pii_flags & PII_FLAGS_COMPAC)) {
- *mp->b_wptr++ = PPP_ALLSTATIONS;
- *mp->b_wptr++ = PPP_UI;
- }
- if (!(p->pii_flags & PII_FLAGS_COMPPROT))
- *mp->b_wptr++ = 0;
- *mp->b_wptr++ = protocol & 0xff;
- for (m1 = m0; m1; m1 = m1->m_next) { /* copy all data */
- bcopy(mtod(m1, char *), (char *) mp->b_wptr, m1->m_len);
- mp->b_wptr += m1->m_len;
- }
- m_freem(m0);
-
- s = splstr();
- putq(p->pii_writeq, mp);
- splx(s);
-
- p->pii_ifnet.if_opackets++;
- INCR(sl_opackets);
- }
- return 0;
- }
-
- /*
- * if_ ioctl requests
- */
- dp_ioctl(ifp, cmd, data)
- register struct ifnet *ifp;
- int cmd;
- caddr_t data;
- {
- register struct ifaddr *ifa = (struct ifaddr *) data;
- register struct ifreq *ifr = (struct ifreq *) data;
- int s = splimp(), error = 0;
-
- if (ifa == NULL ) {
- splx(s);
- return(EFAULT);
- }
-
- switch (cmd) {
- case SIOCSIFFLAGS:
- if (!suser()) {
- error = EPERM;
- break;
- }
- ifp->if_flags &= (IFF_CANTCHANGE); /* clear the flags that can be cleared */
- ifp->if_flags |= (ifr->ifr_flags & ~IFF_CANTCHANGE); /* or in the flags that can
- be changed */
- dp_init(ifp->if_unit);
- break;
- case SIOCGIFFLAGS:
- ifr->ifr_flags = ifp->if_flags;
- break;
- case SIOCSIFADDR:
- if (ifa->ifa_addr.sa_family != AF_INET)
- error = EAFNOSUPPORT;
- break;
- case SIOCSIFDSTADDR:
- if (ifa->ifa_addr.sa_family != AF_INET)
- error = EAFNOSUPPORT;
- break;
-
- #ifndef ifr_mtu
- #define ifr_mtu ifr_metric
- #endif
- case SIOCSIFMTU:
- if (!suser()) {
- error = EPERM;
- break;
- }
- if (ifr->ifr_mtu >
- (4096 - (sizeof(struct ppp_header) + sizeof(u_short)))) {
- error = EINVAL;
- break;
- }
- ifp->if_mtu = ifr->ifr_mtu;
- break;
- case SIOCGIFMTU:
- ifr->ifr_mtu = ifp->if_mtu;
- break;
-
- case SIOCICALLSTAT:
- dp_callstat(&dupii[ifp->if_unit], ifr->ifr_data[0]);
- break;
-
- case SIOCSDPIATIMEO: /* Set Activity Timeouts */
- dp_settimos(&dupii[ifp->if_unit], (u_long *)ifr->ifr_data,
- DP_ATIMEOUTS, DP_NATIMEOUTS);
- break;
- case SIOCGDPIATIMEO: /* Get Activity Timeouts */
- dp_gettimos(&dupii[ifp->if_unit], (u_long *)ifr->ifr_data,
- DP_ATIMEOUTS, DP_NATIMEOUTS);
- break;
-
- case SIOCSDPICTIMEO: /* Set Call Timeouts */
- dp_settimos(&dupii[ifp->if_unit], (u_long *)ifr->ifr_data,
- DP_CTIMEOUTS, DP_NCTIMEOUTS);
- break;
- case SIOCGDPICTIMEO: /* Get Call Timeouts */
- dp_gettimos(&dupii[ifp->if_unit], (u_long *)ifr->ifr_data,
- DP_CTIMEOUTS, DP_NCTIMEOUTS);
- break;
-
- case SIOCGDPIISTATS: /* Get Input Stats */
- dp_gstats(&dupii[ifp->if_unit], (u_int *)ifr->ifr_data, 0);
- break;
-
- case SIOCGDPIOSTATS: /* Get Output Stats */
- dp_gstats(&dupii[ifp->if_unit], (u_int *)ifr->ifr_data, 1);
- break;
-
- default:
- error = EINVAL;
- break;
- }
- splx(s);
- return(error);
- }
-
- static
- dp_gstats(p, stats, out)
- register PII *p;
- register u_int *stats;
- int out;
- {
- #ifdef PPP_STATS
- struct slipstat *ss = &p->pii_stats;
- if (out) {
- stats[0] = ss->sl_obytes;
- stats[1] = ss->sl_opackets;
- stats[2] = ss->sl_oerrors;
- }
- else {
- stats[0] = ss->sl_ibytes;
- stats[1] = ss->sl_ipackets;
- stats[2] = ss->sl_ierrors;
- }
- #endif PPP_STATS
- }
-
- static
- dp_settimos(p, to, t0, nt)
- register PII *p;
- register u_long *to;
- register int t0, nt;
- {
- register int t;
- for (t = 0 ; t < nt ; t++)
- switch (to[t]) {
- case DP_DEF_TIMEOUT:
- break;
- case DP_NO_TIMEOUT:
- p->pii_timo[t0 + t] = DP_NO_TIMEOUT;
- break;
- default:
- p->pii_timo[t0 + t] = to[t] / DP_HZ;
- break;
- }
- /*
- * If we are using certain timeouts, do extra processing
- * on each packet.
- */
- if (p->pii_timo[DP_CTIMEO] == DP_NO_TIMEOUT &&
- p->pii_timo[DP_UTIMEO] == DP_NO_TIMEOUT)
- p->pii_flags &= ~PII_FLAGS_ACTIVE;
- else
- p->pii_flags |= PII_FLAGS_ACTIVE;
-
- DLOG5("dp_settimos: t0 %d nt %d - %d %d %d\n", t0, nt,
- to[t0], to[t0+1], to[t0+2]);
- DLOG5("dp_settimos: timeouts %d %d %d %d %d\n", p->pii_timo[0] * DP_HZ,
- p->pii_timo[1] * DP_HZ, p->pii_timo[2] * DP_HZ,
- p->pii_timo[3] * DP_HZ, p->pii_timo[4] * DP_HZ);
- }
-
- static
- dp_gettimos(p, to, t0, nt)
- register PII *p;
- register u_long *to;
- register int t0, nt;
- {
- register int t;
- for (t = 0 ; t < nt ; t++)
- to[t] = p->pii_timo[t0 + t] * DP_HZ;
- DLOG5("dp_gettimos: timeouts %d %d %d %d %d\n", p->pii_timo[0] * DP_HZ,
- p->pii_timo[1] * DP_HZ, p->pii_timo[2] * DP_HZ,
- p->pii_timo[3] * DP_HZ, p->pii_timo[4] * DP_HZ);
- }
-
- static
- dp_state(p, dustate)
- register PII *p;
- register int dustate;
- {
- if (p->pii_dustate == dustate)
- return;
- p->pii_dustate = dustate;
- p->pii_timer = p->pii_timo[p->pii_dustate];
- p->pii_ftimer = DP_NO_TIMEOUT;
- p->pii_ifnet.if_timer = (p->pii_timer > 0 || p->pii_ftimer > 0) ? DP_HZ : 0;
- #ifdef DEBUGS
- if (dp_if_debug || dp_ftimo_debug)
- log(LOG_INFO, "dp_state: %s %d %d (%d)\n", dus_str[dustate],
- p->pii_timer, p->pii_ftimer, p->pii_ifnet.if_timer);
- #endif
- }
-
- static void
- dp_event(p, timer)
- register PII *p;
- register int timer;
- {
- register int timo;
- p->pii_timer = p->pii_timo[p->pii_dustate];
- switch (timer) {
- #if 0
- case DP_ATIMEO:
- p->pii_ftimer = DP_NO_TIMEOUT;
- break;
- #endif
- case DP_UTIMEO:
- case DP_CTIMEO:
- if ((timo = p->pii_timo[timer]) >= 0 && timo > p->pii_ftimer)
- p->pii_ftimer = timo;
- break;
- }
- p->pii_ifnet.if_timer = (p->pii_timer > 0 || p->pii_ftimer > 0) ? DP_HZ : 0;
- #ifdef DEBUGS
- if (dp_if_debug || dp_ftimo_debug)
- log(LOG_INFO, "dp_event: %s/%s %d %d (%d)\n",
- dus_str[p->pii_dustate], dus_str[timer],
- p->pii_timer, p->pii_ftimer, p->pii_ifnet.if_timer);
- #endif
- }
-
- /*
- * dp_timer() provides for the following state transitions on timeout..
- *
- * State Status New State
- * FAILCALL TIMEOUT DISCON (can try calling again)
- * ACTIVE TIMEOUT DISCON (inactivity timeout)
- * WAITING TIMEOUT FAILCALL (dialer is taking too long)
- */
- static int
- dp_timer(unit)
- int unit;
- {
- register PII *p = &dupii[unit];
- queue_t *q = p->pii_writeq;
- register int s;
-
-
- /* just being cautious by setting up the interrupt priority */
- s = splimp();
-
- /*
- * Count down the timers.
- */
- if (p->pii_timer > 0)
- p->pii_timer--;
- if (p->pii_ftimer > 0)
- p->pii_ftimer--;
-
- #ifdef DEBUGS
- if (dp_if_debug || dp_ftimo_debug)
- log(LOG_INFO, "dp_timer: before %s %d %d\n",
- dus_str[p->pii_dustate], p->pii_timer, p->pii_ftimer);
- #endif
- /*
- * Ignore the fast timer expiration if we have active connections.
- */
- if (p->pii_ftimer == 0 && p->pii_active.da_nactive) {
- DLOGSTATE("dp_timer: fast timer ignored (%s)\n");
- #ifdef DEBUGS
- if (dp_if_debug || dp_ftimo_debug)
- log(LOG_INFO, "dp_timer: fast timer ignored (%s)\n",
- dus_str[p->pii_dustate]);
- #endif
- p->pii_ftimer = DP_NO_TIMEOUT;
- }
-
- /*
- * If we are still counting down, get out of here..
- */
- if (p->pii_timer && p->pii_ftimer) {
- /* Reset the interface timer, and return */
- p->pii_ifnet.if_timer = DP_HZ;
- splx(s);
- return;
- }
-
- #ifdef DEBUGS
- if (dp_if_debug || dp_ftimo_debug)
- log(LOG_INFO, "dp_timer: %stimer expired, state = %s\n",
- p->pii_ftimer == 0 ? "fast " : "", dus_str[p->pii_dustate]);
- #endif
- /*
- * One of the timers counted down to zero..
- */
- switch (p->pii_dustate) {
- case PII_DPS_DOWN:
- case PII_DPS_DISCON:
- /*
- * Do nothing....
- */
- break;
- case PII_DPS_WAITING:
- /*
- * Assume that the dialup program hung, so assume a failed call.
- */
- dp_state(p, PII_DPS_FAILCALL);
- dp_flush(p, q);
- DLOG("dp_timer: unit %d - we never had a line.\n", unit);
- break;
-
- case PII_DPS_ACTIVE:
- /*
- * Shut down the line for now by sending a signal to the PPP process.
- */
- dp_state(p, PII_DPS_DISCON);
- DLOG("dp_timer: sending SIGTERM to PPP process\n", unit);
- putctl1(RD(q), M_PCSIG, SIGTERM);
- break;
-
- case PII_DPS_FAILCALL:
- /*
- * Reenable the line for call attempts.
- */
- dp_state(p, PII_DPS_DISCON);
- break;
-
- default:
- DLOG("dp_timer: unknown state %d\n", p->pii_dustate);
- break;
- }
- splx(s);
- DLOGSTATE("dp_timer: after %s\n");
- }
-
- static void
- dp_active_tinit(tab)
- struct dp_ctab *tab;
- {
- register struct dp_conv *conv = tab->dt_conv;
- register int i;
- for (i = MAX_ACTIVE - 1; i > 0; --i)
- conv[i].dc_next = &conv[i - 1];
- conv[0].dc_next = &conv[MAX_ACTIVE - 1];
- tab->dt_last = &conv[0];
- }
-
- static void
- dp_active_init(act)
- struct dp_active *act;
- {
- bzero((char *)act, sizeof(*act));
- dp_active_tinit(&act->da_ttab);
- dp_active_tinit(&act->da_rtab);
- }
-
-
- static void dp_rstactive();
-
- static void
- dp_active(p, ip, len, xmit)
- register PII *p;
- register struct ip *ip;
- int len;
- int xmit;
- {
- register struct dp_active *act;
- register struct dp_ctab *tab;
- register struct dp_conv *conv;
- register struct tcphdr *th;
- register u_int hlen;
-
- if (!(p->pii_flags & PII_FLAGS_ACTIVE)) {
- dp_event(p, DP_ATIMEO);
- return;
- }
- #ifdef DEBUGS
- act = &p->pii_active;
- #endif
- /*
- * Don't bother with fragments.
- */
- if (len < sizeof(struct ip) || ip->ip_off & htons(0x3fff)) {
- DLOG_ACTIVE("len");
- return;
- }
-
- /*
- * Account for non-tcp traffic.
- */
- if (ip->ip_p != IPPROTO_TCP) {
- DLOG_ACTIVE("nontcp");
- dp_event(p, DP_UTIMEO);
- return;
- }
-
- /*
- * This shouldn't happen, but if it does,
- * Make sure we have enough of the TCP header to be interesting..
- */
- hlen = ip->ip_hl << 2;
- if (len < hlen + sizeof(struct tcphdr)) {
- DLOG_ACTIVE("len2");
- return;
- }
-
- /*
- * Look for the conversation in our table.
- * Check if it is the most recently used (it probably is).
- * If not, search the table in MRU order.
- */
- #ifndef DEBUGS
- act = &p->pii_active;
- #endif
- th = (struct tcphdr *)&((char *)ip)[hlen];
- tab = xmit ? &act->da_ttab : &act->da_rtab;
- conv = tab->dt_last->dc_next;
- act->da_lookups++;
-
- if (ip->ip_src.s_addr != conv->dc_ip_src.s_addr ||
- ip->ip_dst.s_addr != conv->dc_ip_dst.s_addr ||
- *(int *)th != *((int *)&conv->dc_th_sport)) {
- /*
- * Not the most recently used conversation, look through the
- * circularly linked list.
- */
- register struct dp_conv *lconv,
- *last = tab->dt_last;
-
- act->da_misses++;
- do {
- lconv = conv;
- conv = conv->dc_next;
- if (ip->ip_src.s_addr == conv->dc_ip_src.s_addr &&
- ip->ip_dst.s_addr == conv->dc_ip_dst.s_addr &&
- *(int *)th == *((int *)&conv->dc_th_sport)) {
- /*
- * This conversation is in the table somewhere.
- * Move it to the front of the list.
- */
- if (conv == last)
- tab->dt_last = lconv;
- else {
- lconv->dc_next = conv->dc_next;
- conv->dc_next = last->dc_next;
- last->dc_next = conv;
- }
- goto intable;
- }
- } while (conv != last);
-
- /*
- * If the LRU conversation is active, and we have at least one
- * inactive conversation, move the LRU inactive connection to the
- * LRU slot.
- *
- * It was considered best to scan the table again here to make
- * the first table scan quicker since it is executed more frequently.
- */
- if (conv->dc_flags & DC_ACTIVE) {
- register struct dp_conv *linact = (struct dp_conv *)0;
-
- lconv = tab->dt_last;
- conv = lconv->dc_next;
- if (!(conv->dc_flags & DC_ACTIVE))
- linact = lconv;
- do {
- lconv = conv;
- conv = conv->dc_next;
- if (!(conv->dc_flags & DC_ACTIVE))
- linact = lconv;
- } while (conv != last);
- if (linact) {
- conv = linact->dc_next;
- lconv = last;
-
- linact->dc_next = conv->dc_next;
- conv->dc_next = last->dc_next;
- last->dc_next = conv;
- }
- }
- #if 1
- /*
- * With this #ifdef'ed out, the fast timeout will be effectively
- * disabled when more than MAX_ACTIVE (16) conversations are in effect.
- * With this included, MAX_ACTIVE fast connects and disconnects will
- * cause a fast timeout even if there are active conversations.
- */
- if (conv->dc_flags & DC_ACTIVE)
- act->da_nactive--;
- #endif
- /*
- * This conversation is not in our table.
- * Create an entry for it in the least recently used slot.
- */
- tab->dt_last = lconv;
- conv->dc_ip_src.s_addr = ip->ip_src.s_addr;
- conv->dc_ip_dst.s_addr = ip->ip_dst.s_addr;
- *((int *)&conv->dc_th_sport) = *(int *)th;
- conv->dc_flags = DC_ACTIVE;
- act->da_nactive++;
- DLOG_ACTIVE("NEW");
- }
-
- intable:
- if (conv->dc_flags & DC_ACTIVE) {
- if (th->th_flags & (TH_FIN|TH_RST)) {
- /*
- * Conversation shutting down
- */
- conv->dc_flags &= ~DC_ACTIVE;
- act->da_nactive--;
- DLOG_ACTIVE((th->th_flags & TH_FIN) ? "FIN" : "RST");
- }
- }
- else
- if (th->th_flags & TH_SYN) {
- /*
- * Conversation (re)starting
- */
- conv->dc_flags |= DC_ACTIVE;
- act->da_nactive++;
- DLOG_ACTIVE("SYN");
- }
- dp_event(p, act->da_nactive ? DP_ATIMEO : DP_CTIMEO);
- /*
- * On a reset, do special processing.
- */
- if (th->th_flags & TH_RST)
- dp_rstactive(p, ip, len, xmit);
- }
-
- /*
- * A reset affects both halves of a conversation. Here, when a RST
- * happens on half of a conversation, we fake a FIN for the other half
- * since a TCP will never respond to a RST..
- */
- static void
- dp_rstactive(p, ip, len, xmit)
- register PII *p;
- register struct ip *ip;
- int len;
- int xmit;
- {
- #define HDR_SLOP 44
- char revip[sizeof(struct ip)+sizeof(struct tcphdr)+HDR_SLOP];
- register struct ip *ip2 = (struct ip *)revip;
- register struct tcphdr *th, *th2;
- register u_int hlen = ip->ip_hl << 2;
-
- if (hlen + sizeof(struct tcphdr) > sizeof(revip))
- return;
- th = (struct tcphdr *)&((char *)ip)[hlen];
- th2 = (struct tcphdr *)&((char *)ip2)[hlen];
- bcopy((char *)ip, (char *)ip2, hlen);
- th2->th_flags = (th->th_flags & ~TH_RST) | TH_FIN;
- ip2->ip_src = ip->ip_dst;
- ip2->ip_dst = ip->ip_src;
- th2->th_sport = th->th_dport;
- th2->th_dport = th->th_sport;
- dp_active(p, ip2, hlen + sizeof(struct tcphdr), !xmit);
- }
-
- /*
- * This code implements the streams device for communicating connect requests
- * to user-land. This was formerly in a sepearate file (ppp_dial.c),
- * but in the expectation of future updates to allow loadable modules,
- * these two files were merged since one file calls a function in the
- * other file. Loadable modules are apparently picky about that and there
- * is no way to get around the function call..
- */
- #undef DLOG
- #ifdef DEBUGS
- #define DLOG(s,a) if(ppp_dial_debug) log(LOG_INFO, s, a)
- int ppp_dial_debug=0;
- #else
- #define DLOG(s,a) {}
- #endif
-
- static int ppp_dial_open(), ppp_dial_close(), ppp_dial_rsrv(),
- ppp_dial_wput();
-
- static struct module_info ppp_dial_minfo = {
- 0xbae,"pppdial",0, INFPSZ, DP_HIWAT, DP_LOWAT
- };
-
- static struct qinit ppp_dial_rinit = {
- NULL, ppp_dial_rsrv, ppp_dial_open, ppp_dial_close, NULL,
- &ppp_dial_minfo, NULL
- };
- static struct qinit ppp_dial_winit = {
- ppp_dial_wput, NULL, NULL, NULL, NULL,
- &ppp_dial_minfo, NULL
- };
- struct streamtab ppp_dialinfo = {
- &ppp_dial_rinit, &ppp_dial_winit, NULL, NULL, NULL
- };
-
- queue_t *req_q;
-
- static int
- ppp_dial_open(q, dev, flag, sflag)
- queue_t *q;
- dev_t dev;
- int flag,
- sflag;
-
- {
- if (!suser()) {
- u.u_error = EPERM;
- return(OPENFAIL);
- }
- /*
- * Insure this is a normal driver open..
- */
- if (sflag)
- return (OPENFAIL);
-
- /*
- * Insure exclusive access.
- */
- if (q->q_ptr) {
- u.u_error = EBUSY;
- return(OPENFAIL);
- }
-
- q->q_ptr = "ppp daemon running";
- req_q = q;
- DLOG("ppp_dial%d: open\n", minor(dev));
- return dev;
- }
-
- static int
- ppp_dial_close(q)
- queue_t *q; /* queue info */
- {
- req_q = (queue_t *)0;
- q->q_ptr = (char *)0;
- DLOG("ppp_dial: close\n", 0);
- return 0;
- }
-
-
- static int
- ppp_dial_wput(q, mp)
- queue_t *q;
- register mblk_t *mp;
- {
- switch (mp->b_datap->db_type) {
- case M_FLUSH:
- if (*mp->b_rptr & FLUSHW)
- flushq(q, FLUSHDATA);
- if (*mp->b_rptr & FLUSHR) {
- flushq(RD(q), FLUSHDATA);
- *mp->b_rptr &= ~FLUSHW;
- qreply(q, mp);
- }
- else
- freemsg(mp);
- break;
- case M_DATA:
- case M_IOCTL:
- default:
- /*
- * For now, do nothing with stuff written to the stream.
- * Later on, support returning status of dial
- * operations.
- */
- freemsg(mp);
- break;
- }
-
- }
-
- static int
- ppp_dial_rsrv(q)
- queue_t *q;
- {
- register mblk_t *mp;
-
- while ((mp = getq(q)) != NULL) {
- switch (mp->b_datap->db_type) {
- case M_FLUSH:
- if(*mp->b_rptr & FLUSHR)
- flushq(q, FLUSHDATA);
- DLOG("ppp_dial_rsrv: M_FLUSH\n", 0);
- putnext(q, mp); /* send it along too */
- break;
- case M_DATA:
- if (!canput(q->q_next)) {
- #define DISCARD_OLDEST
- #ifdef DISCARD_OLDEST
- register mblk_t *omp;
- /*
- * Throw away something..
- */
- omp = getq(q->q_next);
- freemsg(omp);
- #endif
- #ifdef DISCARD_NEWEST
- freemsg(mp);
- break;
- #endif
- }
- /*
- * Just send this along..
- */
- default:
- DLOG("ppp_dial_rsrv: M_DATA\n", 0);
- putnext(q, mp);
- }
- }
- }
-
- static
- duipreq(m0, dst, ifp, checkit)
- struct mbuf *m0;
- struct sockaddr *dst;
- struct ifnet *ifp;
- int checkit;
- {
- register mblk_t *mp;
- struct dp_req *req;
- struct mbuf *m;
- int s;
- int i;
- int len;
- queue_t *q;
-
- /*
- * If no program is accepting requests, return immediate failure.
- */
- if (!(q = req_q))
- return -1;
- /*
- * Check how much header we have and arrange to send at least
- * DR_MINHDRLEN but not more than DR_MAXHDRLEN to the program
- * handling calls (dpd).
- */
- for (len = 0, m = m0 ; m && len <= DR_MAXHDRLEN ; m = m->m_next)
- len += m->m_len;
- if (len < DR_MINHDRLEN)
- return -1;
- if (len > DR_MAXHDRLEN)
- len = DR_MAXHDRLEN;
-
- /*
- * Allocate the appropriate stream data structure for this request.
- */
- s = splstr();
- mp = allocb(sizeof(struct dp_reqinfo) + len, BPRI_MED);
- if (!mp) {
- splx(s);
- return -1;
- }
-
- /*
- * Fill in the request info.
- */
- req = (struct dp_req *)mp->b_wptr;
- mp->b_wptr += sizeof (struct dp_reqinfo);
- for (i = 0 ; i < sizeof(req->dr_ifname) ; i++)
- if (!(req->dr_ifname[i] = ifp->if_name[i]))
- break;
- for ( i++ ; i < sizeof(req->dr_ifname) ; i++)
- req->dr_ifname[i] = '\0';
- req->dr_ifunit = ifp->if_unit;
- req->dr_flag = checkit ? DP_REQ_CHECKIT : 0;
- bcopy(dst, &req->dr_sin, sizeof(struct sockaddr_in));
- req->dr_hdrlen = len;
- /*
- * Copy the header data, in chunks if necessary.
- */
- for (m = m0 ; len > 0 && m ; m = m->m_next) {
- i = MIN(len, m->m_len);
- bcopy(mtod(m, char *), mp->b_wptr, i);
- len -= i;
- mp->b_wptr += i;
- }
- /*
- * Send this stream stuff to the program.
- */
- putq(q, mp);
- splx(s);
- DLOG("duipreq\n", 0);
- return 0;
- }
-
- /*
- * slcompress.c is included here with small changes, to make loadable
- * module implementation easier... peter@micromuse.co.uk
- */
-
- /*
- * Routines to compress and uncompess tcp packets (for transmission
- * over low speed serial lines.
- *
- * Copyright (c) 1989 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
- * - Initial distribution.
- */
-
- #ifndef SL_NO_STATS
- #define SLINCR(counter) ++comp->counter;
- #else
- #define SLINCR(counter)
- #endif
-
- #define SLBCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n))
- #define SLBCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n))
- #ifndef KERNEL
- #define ovbcopy bcopy
- #endif
-
-
- static void
- sl_compress_init(comp)
- struct slcompress *comp;
- {
- register u_int i;
- register struct cstate *tstate = comp->tstate;
-
- bzero((char *)comp, sizeof(*comp));
- for (i = MAX_STATES - 1; i > 0; --i) {
- tstate[i].cs_id = i;
- tstate[i].cs_next = &tstate[i - 1];
- }
- tstate[0].cs_next = &tstate[MAX_STATES - 1];
- tstate[0].cs_id = 0;
- comp->last_cs = &tstate[0];
- comp->last_recv = 255;
- comp->last_xmit = 255;
- comp->flags = SLF_TOSS;
- }
-
-
- /* ENCODE encodes a number that is known to be non-zero. ENCODEZ
- * checks for zero (since zero has to be encoded in the long, 3 byte
- * form).
- */
- #define ENCODE(n) { \
- if ((u_short)(n) >= 256) { \
- *cp++ = 0; \
- cp[1] = (n); \
- cp[0] = (n) >> 8; \
- cp += 2; \
- } else { \
- *cp++ = (n); \
- } \
- }
- #define ENCODEZ(n) { \
- if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
- *cp++ = 0; \
- cp[1] = (n); \
- cp[0] = (n) >> 8; \
- cp += 2; \
- } else { \
- *cp++ = (n); \
- } \
- }
-
- #define DECODEL(f) { \
- if (*cp == 0) {\
- (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
- cp += 3; \
- } else { \
- (f) = htonl(ntohl(f) + (u_long)*cp++); \
- } \
- }
-
- #define DECODES(f) { \
- if (*cp == 0) {\
- (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
- cp += 3; \
- } else { \
- (f) = htons(ntohs(f) + (u_long)*cp++); \
- } \
- }
-
- #define DECODEU(f) { \
- if (*cp == 0) {\
- (f) = htons((cp[1] << 8) | cp[2]); \
- cp += 3; \
- } else { \
- (f) = htons((u_long)*cp++); \
- } \
- }
-
-
- static u_char
- sl_compress_tcp(m, ip, comp, compress_cid)
- struct mbuf *m;
- register struct ip *ip;
- struct slcompress *comp;
- int compress_cid;
- {
- register struct cstate *cs = comp->last_cs->cs_next;
- register u_int hlen = ip->ip_hl;
- register struct tcphdr *oth;
- register struct tcphdr *th;
- register u_int deltaS, deltaA;
- register u_int changes = 0;
- u_char new_seq[16];
- register u_char *cp = new_seq;
-
- /*
- * Bail if this is an IP fragment or if the TCP packet isn't
- * `compressible' (i.e., ACK isn't set or some other control bit is
- * set). (We assume that the caller has already made sure the
- * packet is IP proto TCP).
- */
- if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40)
- return (TYPE_IP);
-
- th = (struct tcphdr *)&((int *)ip)[hlen];
- if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
- return (TYPE_IP);
- /*
- * Packet is compressible -- we're going to send either a
- * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need
- * to locate (or create) the connection state. Special case the
- * most recently used connection since it's most likely to be used
- * again & we don't have to do any reordering if it's used.
- */
- SLINCR(sls_packets)
- if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
- ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
- *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
- /*
- * Wasn't the first -- search for it.
- *
- * States are kept in a circularly linked list with
- * last_cs pointing to the end of the list. The
- * list is kept in lru order by moving a state to the
- * head of the list whenever it is referenced. Since
- * the list is short and, empirically, the connection
- * we want is almost always near the front, we locate
- * states via linear search. If we don't find a state
- * for the datagram, the oldest state is (re-)used.
- */
- register struct cstate *lcs;
- register struct cstate *lastcs = comp->last_cs;
-
- do {
- lcs = cs; cs = cs->cs_next;
- SLINCR(sls_searches)
- if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
- && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
- && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl])
- goto found;
- } while (cs != lastcs);
-
- /*
- * Didn't find it -- re-use oldest cstate. Send an
- * uncompressed packet that tells the other side what
- * connection number we're using for this conversation.
- * Note that since the state list is circular, the oldest
- * state points to the newest and we only need to set
- * last_cs to update the lru linkage.
- */
- SLINCR(sls_misses)
- comp->last_cs = lcs;
- hlen += th->th_off;
- hlen <<= 2;
- goto uncompressed;
-
- found:
- /*
- * Found it -- move to the front on the connection list.
- */
- if (cs == lastcs)
- comp->last_cs = lcs;
- else {
- lcs->cs_next = cs->cs_next;
- cs->cs_next = lastcs->cs_next;
- lastcs->cs_next = cs;
- }
- }
-
- /*
- * Make sure that only what we expect to change changed. The first
- * line of the `if' checks the IP protocol version, header length &
- * type of service. The 2nd line checks the "Don't fragment" bit.
- * The 3rd line checks the time-to-live and protocol (the protocol
- * check is unnecessary but costless). The 4th line checks the TCP
- * header length. The 5th line checks IP options, if any. The 6th
- * line checks TCP options, if any. If any of these things are
- * different between the previous & current datagram, we send the
- * current datagram `uncompressed'.
- */
- oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
- deltaS = hlen;
- hlen += th->th_off;
- hlen <<= 2;
-
- if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] ||
- ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] ||
- ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] ||
- th->th_off != oth->th_off ||
- (deltaS > 5 &&
- SLBCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
- (th->th_off > 5 &&
- SLBCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
- goto uncompressed;
-
- /*
- * Figure out which of the changing fields changed. The
- * receiver expects changes in the order: urgent, window,
- * ack, seq (the order minimizes the number of temporaries
- * needed in this section of code).
- */
- if (th->th_flags & TH_URG) {
- deltaS = ntohs(th->th_urp);
- ENCODEZ(deltaS);
- changes |= NEW_U;
- } else if (th->th_urp != oth->th_urp)
- /* argh! URG not set but urp changed -- a sensible
- * implementation should never do this but RFC793
- * doesn't prohibit the change so we have to deal
- * with it. */
- goto uncompressed;
-
- if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) {
- ENCODE(deltaS);
- changes |= NEW_W;
- }
-
- if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) {
- if (deltaA > 0xffff)
- goto uncompressed;
- ENCODE(deltaA);
- changes |= NEW_A;
- }
-
- if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) {
- if (deltaS > 0xffff)
- goto uncompressed;
- ENCODE(deltaS);
- changes |= NEW_S;
- }
-
- switch(changes) {
-
- case 0:
- /*
- * Nothing changed. If this packet contains data and the
- * last one didn't, this is probably a data packet following
- * an ack (normal on an interactive connection) and we send
- * it compressed. Otherwise it's probably a retransmit,
- * retransmitted ack or window probe. Send it uncompressed
- * in case the other side missed the compressed version.
- */
- if (ip->ip_len != cs->cs_ip.ip_len &&
- ntohs(cs->cs_ip.ip_len) == hlen)
- break;
-
- /* (fall through) */
-
- case SPECIAL_I:
- case SPECIAL_D:
- /*
- * actual changes match one of our special case encodings --
- * send packet uncompressed.
- */
- goto uncompressed;
-
- case NEW_S|NEW_A:
- if (deltaS == deltaA &&
- deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
- /* special case for echoed terminal traffic */
- changes = SPECIAL_I;
- cp = new_seq;
- }
- break;
-
- case NEW_S:
- if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
- /* special case for data xfer */
- changes = SPECIAL_D;
- cp = new_seq;
- }
- break;
- }
-
- deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
- if (deltaS != 1) {
- ENCODEZ(deltaS);
- changes |= NEW_I;
- }
- if (th->th_flags & TH_PUSH)
- changes |= TCP_PUSH_BIT;
- /*
- * Grab the cksum before we overwrite it below. Then update our
- * state with this packet's header.
- */
- deltaA = ntohs(th->th_sum);
- SLBCOPY(ip, &cs->cs_ip, hlen);
-
- /*
- * We want to use the original packet as our compressed packet.
- * (cp - new_seq) is the number of bytes we need for compressed
- * sequence numbers. In addition we need one byte for the change
- * mask, one for the connection id and two for the tcp checksum.
- * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how
- * many bytes of the original packet to toss so subtract the two to
- * get the new packet size.
- */
- deltaS = cp - new_seq;
- cp = (u_char *)ip;
- if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
- comp->last_xmit = cs->cs_id;
- hlen -= deltaS + 4;
- cp += hlen;
- *cp++ = changes | NEW_C;
- *cp++ = cs->cs_id;
- } else {
- hlen -= deltaS + 3;
- cp += hlen;
- *cp++ = changes;
- }
- m->m_len -= hlen;
- m->m_off += hlen;
- *cp++ = deltaA >> 8;
- *cp++ = deltaA;
- SLBCOPY(new_seq, cp, deltaS);
- SLINCR(sls_compressed)
- return (TYPE_COMPRESSED_TCP);
-
- /*
- * Update connection state cs & send uncompressed packet ('uncompressed'
- * means a regular ip/tcp packet but with the 'conversation id' we hope
- * to use on future compressed packets in the protocol field).
- */
- uncompressed:
- SLBCOPY(ip, &cs->cs_ip, hlen);
- ip->ip_p = cs->cs_id;
- comp->last_xmit = cs->cs_id;
- return (TYPE_UNCOMPRESSED_TCP);
- }
-
-
- static int
- sl_uncompress_tcp(bufp, len, type, comp)
- u_char **bufp;
- int len;
- u_int type;
- struct slcompress *comp;
- {
- register u_char *cp;
- register u_int hlen, changes;
- register struct tcphdr *th;
- register struct cstate *cs;
- register struct ip *ip;
-
- switch (type) {
-
- case TYPE_UNCOMPRESSED_TCP:
- ip = (struct ip *) *bufp;
- if (ip->ip_p >= MAX_STATES)
- goto bad;
- cs = &comp->rstate[comp->last_recv = ip->ip_p];
- comp->flags &=~ SLF_TOSS;
- ip->ip_p = IPPROTO_TCP;
- hlen = ip->ip_hl;
- hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off;
- hlen <<= 2;
- SLBCOPY(ip, &cs->cs_ip, hlen);
- cs->cs_ip.ip_sum = 0;
- cs->cs_hlen = hlen;
- SLINCR(sls_uncompressedin)
- return (len);
-
- default:
- goto bad;
-
- case TYPE_COMPRESSED_TCP:
- break;
- }
- /* We've got a compressed packet. */
- SLINCR(sls_compressedin)
- cp = *bufp;
- changes = *cp++;
- if (changes & NEW_C) {
- /* Make sure the state index is in range, then grab the state.
- * If we have a good state index, clear the 'discard' flag. */
- if (*cp >= MAX_STATES)
- goto bad;
-
- comp->flags &=~ SLF_TOSS;
- comp->last_recv = *cp++;
- } else {
- /* this packet has an implicit state index. If we've
- * had a line error since the last time we got an
- * explicit state index, we have to toss the packet. */
- if (comp->flags & SLF_TOSS) {
- SLINCR(sls_tossed)
- return (0);
- }
- }
- cs = &comp->rstate[comp->last_recv];
- hlen = cs->cs_ip.ip_hl << 2;
- th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
- th->th_sum = htons((*cp << 8) | cp[1]);
- cp += 2;
- if (changes & TCP_PUSH_BIT)
- th->th_flags |= TH_PUSH;
- else
- th->th_flags &=~ TH_PUSH;
-
- switch (changes & SPECIALS_MASK) {
- case SPECIAL_I:
- {
- register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
- th->th_ack = htonl(ntohl(th->th_ack) + i);
- th->th_seq = htonl(ntohl(th->th_seq) + i);
- }
- break;
-
- case SPECIAL_D:
- th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
- - cs->cs_hlen);
- break;
-
- default:
- if (changes & NEW_U) {
- th->th_flags |= TH_URG;
- DECODEU(th->th_urp)
- } else
- th->th_flags &=~ TH_URG;
- if (changes & NEW_W)
- DECODES(th->th_win)
- if (changes & NEW_A)
- DECODEL(th->th_ack)
- if (changes & NEW_S)
- DECODEL(th->th_seq)
- break;
- }
- if (changes & NEW_I) {
- DECODES(cs->cs_ip.ip_id)
- } else
- cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
-
- /*
- * At this point, cp points to the first byte of data in the
- * packet. If we're not aligned on a 4-byte boundary, copy the
- * data down so the ip & tcp headers will be aligned. Then back up
- * cp by the tcp/ip header length to make room for the reconstructed
- * header (we assume the packet we were handed has enough space to
- * prepend 128 bytes of header). Adjust the length to account for
- * the new header & fill in the IP total length.
- */
- len -= (cp - *bufp);
- if (len < 0)
- /* we must have dropped some characters (crc should detect
- * this but the old slip framing won't) */
- goto bad;
-
- if ((int)cp & 3) {
- if (len > 0)
- (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len);
- cp = (u_char *)((int)cp &~ 3);
- }
- cp -= cs->cs_hlen;
- len += cs->cs_hlen;
- cs->cs_ip.ip_len = htons(len);
- SLBCOPY(&cs->cs_ip, cp, cs->cs_hlen);
- *bufp = cp;
-
- /* recompute the ip header checksum */
- {
- register u_short *bp = (u_short *)cp;
- for (changes = 0; hlen > 0; hlen -= 2)
- changes += *bp++;
- changes = (changes & 0xffff) + (changes >> 16);
- changes = (changes & 0xffff) + (changes >> 16);
- ((struct ip *)cp)->ip_sum = ~ changes;
- }
- return (len);
- bad:
- comp->flags |= SLF_TOSS;
- SLINCR(sls_errorin)
- return (0);
- }
-
- #ifdef LOADABLE
-
- #define LOG_INUSE 1
-
- struct cdevsw ppp_cdevsw = {
- 0, 0, 0, 0, 0, 0, 0, 0, &ppp_dialinfo, 0
- };
-
- static struct log {
- char flags;
- char nr;
- } dp_if_log[NDP], ppp_dial_log[NDP];
-
- static struct vdldrv ppp_dial_vd = {
- VDMAGIC_PSEUDO,
- "Dialup PPP Interface",
- #if defined(sun4c) || defined(sun4m)
- NULL,
- #else
- (struct mb_ctlr *)NULL,
- (struct mb_driver *)NULL,
- (struct mb_device *)NULL,
- NULL,
- NULL,
- #endif
- NULL,
- &ppp_cdevsw,
- 0,
- 0,
- };
-
- static struct fmodsw *fmod_dp_if;
- static struct fmodsw *fmod_ppp_dial;
-
- dpmod_init(fc,vdp,vdi,vds)
- unsigned int fc;
- struct vddrv *vdp;
- addr_t vdi;
- struct vdstat *vds;
- {
- dp_if_init(fc, vdp, vdi, vds);
- ppp_dial_init(fc, vdp, vdi, vds);
- return 0;
- }
-
-
- static
- dp_if_init(fc,vdp,vdi,vds)
- unsigned int fc;
- struct vddrv *vdp;
- addr_t vdi;
- struct vdstat *vds;
- {
- register int i;
- register struct dp_if_info *p;
- switch(fc) {
- case VDLOAD:
- {
- register int i;
- for(i = 0; i < fmodcnt; i++) {
- if(fmodsw[i].f_str == NULL)
- break;
- }
- if(i == fmodcnt)
- return(ENODEV);
- fmod_dp_if = &fmodsw[i];
- fmod_dp_if->f_str = &dp_ifinfo;
- bcopy(dp_minfo.mi_idname, fmod_dp_if->f_name, FMNAMESZ);
- for (i = 0; i < NDP; i++)
- dp_attach(i);
- return 0;
- }
-
- /* Paul Fox says you only need this line if you have a real device
- * to add to the cdevsw/bdevsw structures, so this should be safe :-)
- * (It seems to work) It goes above by the way.
- *
- * vdp->vdd_vdtab = (struct vdlinkage *) &dp_if_vd;
- */
- case VDUNLOAD:
- {
- int dev;
- for (dev = 0; dev < NDP; dev++)
- if (dupii[dev].pii_flags & PII_FLAGS_INUSE)
- return (EBUSY);
- }
- for (i = 0, p = dupii; i < NDP; i++, p++) {
- /***********************************************/
- /* Loadable driver needs to detach from */
- /* ifnet structure otherwise we panic */
- /* system as soon as if_slowtimo() goes */
- /* off because it has a list pointing to */
- /* the memory which will have been */
- /* deallocated. */
- /***********************************************/
- if (p->pii_flags & PII_FLAGS_ATTACHED) {
- if (dp_detach(p) == 0)
- return EBUSY;
- p->pii_flags &= ~PII_FLAGS_ATTACHED;
- }
- fmod_dp_if->f_name[0] = '\0';
- fmod_dp_if->f_str = NULL;
- }
- return 0;
- case VDSTAT:
- return 0;
- default:
- return EIO;
- }
- }
-
- static
- ppp_dial_init(fc,vdp,vdi,vds)
- unsigned int fc;
- struct vddrv *vdp;
- addr_t vdi;
- struct vdstat *vds;
- {
- register int i;
- switch(fc) {
- case VDLOAD:
- {
- for(i=0; i < fmodcnt; i++) {
- if(fmodsw[i].f_str == NULL)
- break;
- }
- if(i == fmodcnt)
- return(ENODEV);
- fmod_ppp_dial = &fmodsw[i];
- fmod_ppp_dial->f_str = &ppp_dialinfo;
- bcopy(ppp_dial_minfo.mi_idname, fmod_ppp_dial->f_name, FMNAMESZ);
- vdp->vdd_vdtab = (struct vdlinkage *) &ppp_dial_vd;
- return 0;
- }
- case VDUNLOAD:
- {
- for (i = 0; i < NDP; i++)
- if (ppp_dial_log[i].flags & LOG_INUSE)
- return (EIO);
- fmod_ppp_dial->f_name[0] = '\0';
- fmod_ppp_dial->f_str = NULL;
- return 0;
- }
- case VDSTAT:
- return 0;
- default:
- return EIO;
- }
- }
-
- /**********************************************************************/
- /* Routine to detach a PPP device from the ifnet structure (list */
- /* of interfaces). Kernel doesn't provide any routines for doing */
- /* this for loadable device drivers and we must avoid panicing */
- /* the system. */
- /**********************************************************************/
- static int
- dp_detach(pp)
- register struct dp_if_info *pp;
- { struct ifnet **p = &ifnet;
- struct ifnet *ifp = &pp->pii_ifnet;
-
- while (*p) {
- if (*p == ifp) {
- *p = ifp->if_next;
- return 1;
- }
- p = &((*p)->if_next);
- }
- return 0;
- }
-
- #endif /* LOADABLE */
- #endif NDP > 0
-