home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Dialup IP driver interface.
- ** Based heavily on 4.3 slip driver.
- ** Copyright (c) 1991 Bolt Beranek and Newman, Inc.
- ** All rights reserved.
- **
- ** Redistribution and use in source and binary forms are permitted
- ** provided that: (1) source distributions retain this entire copyright
- ** notice and comment, and (2) distributions including binaries display
- ** the following acknowledgement: ``This product includes software
- ** developed by Bolt Beranek and Newman, Inc. and CREN/CSNET'' in the
- ** documentation or other materials provided with the distribution and in
- ** all advertising materials mentioning features or use of this software.
- ** Neither the name of Bolt Beranek and Newman nor CREN/CSNET may 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
- ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
- #include "du.h"
- #if NDU > 0
-
- #define DEBUG
-
- #include "../h/param.h"
- #include "../h/mbuf.h"
- #include "../h/buf.h"
- #include "../h/dk.h"
- #include "../h/socket.h"
- #include "../h/ioctl.h"
- #include "../h/file.h"
- #include "../h/tty.h"
- #include "../h/errno.h"
- #include "../net/if.h"
- #include "../net/netisr.h"
- #include "../net/route.h"
- #include "../netinet/in.h"
- #include "../netinet/in_systm.h"
- #ifdef vax
- #include "../netinet/in_var.h"
- #endif /* vax */
- #include "../netinet/ip.h"
- #include "../net/if_du.h"
- #ifdef vax
- #include "../vax/mtpr.h"
- #ifdef ultrix
- #ifndef PRE_ULTRIX_3_0
- #include "../rpc/types.h" /* Needed for Ultrix V3.0 and later */
- #endif /* PRE_ULTRIX_3_0 */
- #endif /* ultrix */
- #endif /* vax */
-
-
-
- /*
- ** Shortcuts for use with duioctl.
- */
- #ifdef vax
- #define DATAVAL(p) (((struct ifreq *)p)->ifr_data)
- #define GET_DATA(p) DATAVAL(p)
- #define SET_DATA(p, d) DATAVAL(p) = (caddr_t)(d)
- #else
- #define DATAVAL(p) (*((int *)p))
- #define GET_DATA(p) DATAVAL(p)
- #define SET_DATA(p, d) DATAVAL(p) = (d)
- #endif /* vax */
-
-
- /*
- ** DMTU is now a hard limit on the input packet site. It must be
- ** less than CLBYTES - sizeof(struct ifnet *).
- */
- #define DUMTU 1006
-
- /*
- ** Timeout parameters and clist usage parameters.
- */
- #define DU_HZ 5 /* five second granularity */
- #define DEFAULT_INACTIVITY_TIME (60 * 5) /* 5 minutes */
- #define DIAL_MONITORTIMEOUT (4 * DU_HZ)
- #define CLISTRESERVE (ds->ds_mtu - 6)
- #define DU_HIWAT (ds->ds_mtu - 6)
-
-
- /*
- ** Escape sequences for framing
- */
- #define FRAME_END 0xC0 /* Frame End */
- #define FRAME_ESCAPE 0xDB /* Frame Esc */
- #define TRANS_FRAME_END 0xDC /* transposed frame end */
- #define TRANS_FRAME_ESCAPE 0xDD /* transposed frame esc */
-
- /*
- ** Packet types.
- */
- #define DUT_IP 03 /* IP packet */
- #define DUT_CP 02 /* Control packet */
- #define DUT_XX 01 /* Reserved for future use */
- #define DUT_EXT 00 /* extended -- leader contains type */
-
- /*
- ** Line header.
- */
- struct du_hdr {
- #ifdef vax
- u_char
- duh_hopcnt:4, /* hop count -- ignored */
- duh_handling:2, /* routing mechanism used -- ignored */
- duh_type:2; /* type -- used */
- #else
- u_char
- duh_type:2,
- duh_handling:2,
- duh_hopcnt:4;
- #endif /* vax */
- u_char duh_dest;
- };
-
-
- struct du_softc du_softc[NDU];
- struct globdialstats globdialstats = { NDU };
- int du_attached = 0;
-
- #ifdef vax
- #define t_du T_LINEP
- #else
- #define t_du t_linep
- #endif /* vax */
-
- #ifdef DEBUG
-
- #define D_ICHAR 0x0001
- #define D_TIMER 0x0002
- #define D_IPKT 0x0004
- #define D_OCHAR 0x0008
- #define D_OPKT 0x0010
- #define D_OUTPUT 0x0020
- #define D_INPUT 0x0040
- #define D_IOCTL 0x0080
- #define D_TRACE 0x0100
- #define D_INFO 0x0200
-
- int dial_debug =
- /* D_ICHAR + */
- /* D_TIMER + */
- /* D_IPKT + */
- /* D_OCHAR + */
- /* D_OPKT + */
- /* D_OUTPUT + */
- /* D_INPUT + */
- /* D_IOCTL + */
- /* D_TRACE + */
- /* D_INFO + */
- 0;
- #define DDEBUG(flag, format, a1, a2, a3) \
- if ((flag) & dial_debug) printf(format, a1, a2, a3); else
- #else
- #define DDEBUG(flag, format, a1, a2, a3) /* NULL */
- #endif /* DEBUG */
-
-
- /*
- ** du_softc Indexing code
- ** See also duattach and dutioctl.
- */
- #ifdef SAFE_DU_INDEX
- #define DU_Index(ifp) ((((ifp)->if_name[2] - 'a') * 10) + (ifp)->if_unit)
- #else
- static int
- DU_Index(ifp)
- struct ifnet *ifp;
- {
- register char *p;
- int i;
-
- /* Check to see if the input looks real or not */
- p = ifp->if_name;
- if (p[0] != 'd' || p[1] != 'u'
- || p[2] < 'a' || p[2] > 'z' || p[3] != 0
- || ifp->if_unit < 0 || ifp->if_unit > 9) {
- printf("DU_Index: WARNING: struct ifnet ifp is not a du interface.\n");
- printf("DU_Index: Interface is \"%s\", Unit is %d\n",
- ifp->if_name, ifp->if_unit);
- return(0); /* XXX Panic? */
- }
-
- i = ((p[2] - 'a') * 10) + ifp->if_unit;
- DDEBUG(D_INFO, "DU_Index: if_name = \"%s\", if_unit = %d, index = %d\n",
- ifp->if_name, ifp->if_unit, i);
- return(i);
- }
- #endif /* SAFE_DU_INDEX */
-
- int duoutput(), duioctl(), dutimer();
-
-
-
- /*
- ** TTY LINE DISCIPLINE ROUTINES
- */
-
- /*
- ** Open line.
- */
- /* ARGSUSED */
- dutopen(dev, tp)
- dev_t dev;
- register struct tty *tp;
- {
- DDEBUG(D_OUTPUT, "dutopen line %d\n", tp->t_dev, 0, 0);
- if (!suser())
- return(EPERM);
-
- if (tp->t_line == DUDISC)
- return(EBUSY);
-
- /* Unlike SLIP, we don't attach here. */
- return(0);
- }
-
-
- /*
- ** Close line. Detach the tty from the du. Mimics part of ttyclose().
- */
- dutclose(tp)
- struct tty *tp;
- {
- DDEBUG(D_TRACE, "dutclose line %x\n", tp->t_dev, 0, 0);
- ttywflush(tp);
- tp->t_line = 0;
- if (tp->t_du) {
- dutnetclose(tp->t_du);
- tp->t_du = NULL;
- }
- }
-
-
- /*
- ** Clean up the net interface when a connection is closed or abandoned.
- ** This is separate from dutclose since we may not have a line when we
- ** call this.
- */
- dutnetclose(ds)
- struct du_softc *ds;
- {
- struct mbuf *m;
- int s;
-
- #ifdef DEBUG
- if (ds)
- DDEBUG(D_TRACE, "dutnetclose ds %x dstty %x\n", ds, ds->ds_ttyp, 0);
- else
- DDEBUG(D_TRACE, "dutnetclose ds %x\n", ds, 0, 0);
- #endif /* DEBUG */
-
- if (ds) {
- s = splimp(); /* paranoid; splnet probably ok */
- /* inactive line */
- ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL);
- if (ds->ds_ttyp)
- ds->ds_ttyp->t_du = NULL;
-
- if (ds->ds_buf) {
- #ifdef vax
- #ifdef ultrix
- #ifndef PRE_ULTRIX_3_0
- kmem_free((caddr_t)ds->ds_buf, KM_DEVBUF);
- #else
- km_free((caddr_t)ds->ds_buf, ds->ds_mtu);
- #endif /* PRE_ULTRIX_3_0 */
- #else
- /* BSD */
- MCLFREE((struct mbuf *)ds->ds_buf);
- #endif /* ultrix */
- #else /* sun */
- kmem_free((caddr_t)ds->ds_buf, ds->ds_mtu);
- #endif /* vax */
- ds->ds_buf = NULL;
- }
-
- /* Clear queues. */
- while (ds->ds_if.if_snd.ifq_len > 0) {
- IF_DEQUEUE(&ds->ds_if.if_snd, m);
- IF_DROP(&ds->ds_if.if_snd);
- m_freem(m);
- }
- splx(s);
-
- if (ds->ds_ttyp) {
- /* tell application to go away */
- DDEBUG(D_TRACE, "netclose: sending signal %d\n",
- ds->ds_ttyp->t_pgrp, 0, 0);
- gsignal(ds->ds_ttyp->t_pgrp, SIGHUP);
- gsignal(ds->ds_ttyp->t_pgrp, SIGCONT);
- ds->ds_ttyp = NULL;
- }
- }
- }
-
-
- /*
- ** Handle modem state changes; basically line drops.
- */
- dutmodem(tp, flag)
- register struct tty *tp;
- int flag;
- {
- DDEBUG(D_TRACE, "dutmodem (Did we lose carrier?)\n", 0, 0, 0);
- if (!flag) {
- /* Lost carrier. */
- tp->t_state &= ~TS_CARR_ON;
- if (tp->t_state & TS_ISOPEN && !(tp->t_flags & NOHANG)) {
- DDEBUG(D_TRACE, "dutmodem kill %d\n", tp->t_pgrp, 0, 0);
- gsignal(tp->t_pgrp, SIGHUP);
- gsignal(tp->t_pgrp, SIGCONT);
- return(0);
- }
- }
- else {
- /* Carrier now on. */
- tp->t_state |= TS_CARR_ON;
- }
- return(1);
- }
-
- /*
- ** IOCTL. Attach to TTY, get unit number.
- */
- /* ARGSUSED */
- dutioctl(tp, cmd, data, flag)
- struct tty *tp;
- int cmd;
- caddr_t data;
- int flag;
- {
- struct ifreq *ifr;
- struct du_softc *ds;
- register char *p;
- int metric;
-
- DDEBUG(D_TRACE, "dutioctl: line %d cmd 0x%x\n", tp->t_dev, cmd, 0);
- if (tp == NULL)
- return(ENOTTY);
-
- if (!du_attached) {
- printf("dutioctl: Used du device before attach\n");
- return (EINVAL);
- }
-
- switch (cmd) {
- case SIOCSIFADDR:
- ifr = (struct ifreq *)data;
- p = ifr->ifr_name;
- /* Does this have the correct form? */
- if (p[0] != 'd' || p[1] != 'u'
- || p[2] < 'a' || p[2] > 'z' || p[3] < '0' || p[3] > '9'
- || p[4] != '\0') {
- DDEBUG(D_IOCTL, "dutioctl: Bad du device \"%s\"\n", p, 0, 0);
- return(EINVAL);
- }
-
- /* Extract the index and verify. */
- DDEBUG(D_IOCTL, "dutioctl: du device name = \"%s\"\n", p, 0, 0);
- metric = ((p[2] - 'a') * 10) + (p[3] - '0');
- DDEBUG(D_IOCTL, "dutioctl: name %s metric %d\n", p, metric, 0);
- if (metric < 0 || metric >= NDU)
- return(EINVAL);
- ds = &du_softc[metric];
-
- /* already busy */
- if (ds->ds_flags & DS_LACTIVE)
- return(EIO);
- if (duinit(ds) == 0)
- return(ENOBUFS);
-
- ds->ds_ilen = 0;
- tp->t_du = (caddr_t)ds;
- /* flush out the line */
- ttyflush(tp, FREAD|FWRITE);
-
- ds->ds_flags |= DS_LACTIVE;
- ds->ds_flags &= ~DS_LWAITING;
- ds->ds_timer = ds->ds_atimo;
- ds->ds_if.if_timer = DU_HZ;
- /* and try to start I/O on device */
- ds->ds_ttyp = tp;
- ds->ds_if.if_flags |= IFF_UP;
-
- dutstart(ds->ds_ttyp);
- return(0);
-
- /* slip uses this to get device number, do we care? */
- case TIOCGETD:
- *(int *)data = DU_Index(&((struct du_softc *)tp->t_du)->ds_if);
- return(0);
- }
- return(-1);
- }
-
-
- /*
- ** Copy data buffer to mbuf chain leave space for interface pointer.
- */
- struct mbuf *
- du_btom(ds, len)
- struct du_softc *ds;
- register int len;
- {
- register caddr_t cp;
- register struct mbuf *m, **mp;
- register unsigned int count;
- int first;
- struct mbuf *top;
-
- first = 1;
- top = NULL;
- for (cp = ds->ds_buf, mp = ⊤ len > 0; mp = &m->m_next, len -= count) {
- MGET(m, M_DONTWAIT, MT_DATA);
- if ((*mp = m) == NULL) {
- m_freem(top);
- return(NULL);
- }
- #ifdef BSD
- if (first) {
- m->m_off += sizeof(struct ifnet *);
- count = MIN(len, MLEN - sizeof(struct ifnet *));
- first = 0;
- }
- else
- #endif /* BSD */
- count = MIN(len, MLEN);
- bcopy(cp, mtod(m, caddr_t), count);
- m->m_len = count;
- cp += count;
- }
-
- return(top);
- }
-
-
- /*
- ** Receiver interrupt.
- */
- dutinput(c, tp)
- register int c;
- register struct tty *tp;
- {
- register struct du_softc *ds;
- register struct mbuf *m;
- struct du_hdr ldr;
- int s;
-
- DDEBUG(D_ICHAR, "dutinput\n", 0, 0, 0);
- tk_nin++;
-
- /* Handle spurious interrupts before the SIOCSIFADDR is done. */
- ds = (struct du_softc *)tp->t_du;
- if (ds < &du_softc[0] || ds > &du_softc[NDU])
- return;
-
- DDEBUG(D_INPUT,"dutinput tp = x%x\n", tp, 0, 0);
- if (ds == NULL || !(ds->ds_flags & DS_LACTIVE))
- return;
-
- ds->ds_cchr++;
-
- c &= 0xFF;
- DDEBUG(D_ICHAR, "dutinput flags %x len %d c= x%x\n",
- ds->ds_flags, ds->ds_ilen, c);
- if (ds->ds_flags & DS_ESCAPED) {
- ds->ds_flags &= ~DS_ESCAPED;
- switch (c) {
- default:
- ds->ds_if.if_ierrors++;
- ds->ds_mp = ds->ds_buf;
- ds->ds_ilen = 0;
- return;
- case TRANS_FRAME_ESCAPE:
- ds->ds_resc++;
- c = FRAME_ESCAPE;
- break;
- case TRANS_FRAME_END:
- ds->ds_resc++;
- c = FRAME_END;
- break;
- }
- }
- else {
- switch (c) {
- case FRAME_END:
- if (ds->ds_ilen == 0)
- return;
- m = du_btom(ds, ds->ds_ilen);
- if (m == NULL) {
- ds->ds_if.if_ierrors++;
- return;
- }
- ds->ds_mp = ds->ds_buf;
- ds->ds_ilen = 0;
- ds->ds_if.if_ipackets++;
- globdialstats.gds_ipln++;
- #ifdef BSD
- *mtod(m, struct ifnet**) = &ds->ds_if;
- #endif /* BSD */
- DDEBUG(D_INPUT,"dutinput: IP PKT\n", 0, 0, 0);
- globdialstats.gds_opup++;
- ds->ds_cpsip++;
- s = splimp();
- if (IF_QFULL(&ipintrq)) {
- IF_DROP(&ipintrq);
- ds->ds_if.if_ierrors++;
- m_freem(m);
- }
- else {
- IF_ENQUEUE(&ipintrq, m);
- schednetisr(NETISR_IP);
- }
- ds->ds_timer = ds->ds_atimo;
- splx(s);
- return;
- case FRAME_ESCAPE:
- ds->ds_flags |= DS_ESCAPED;
- return;
- }
- }
-
- if (++ds->ds_ilen > ds->ds_mtu) {
- ds->ds_if.if_ierrors++;
- ds->ds_mp = ds->ds_buf;
- ds->ds_ilen = 0;
- return;
- }
-
- *ds->ds_mp++ = c;
- }
-
-
-
- /*
- ** Start output on interface. Get another datagram to send from the
- ** interface queue and map it to the interface before starting output.
- */
- dutstart(tp)
- register struct tty *tp;
- {
- register struct du_softc *ds;
- register struct mbuf *m;
- register int len;
- register u_char *cp;
- int flush, nd, np, n, s;
- struct mbuf *m2;
- extern int cfreecount;
-
- if (tp == NULL)
- return(ENOTTY);
-
- ds = (struct du_softc *)tp->t_du;
- DDEBUG(D_TRACE, "dutstart for \"%s%d\" nc = %d\n",
- ds->ds_if.if_name, ds->ds_if.if_unit, tp->t_outq.c_cc);
-
- for ( ; ; ) {
- /* If there is more in the output queue, just send it now. We are
- * being called in lieu of ttstart and must do what it would. */
- if (tp->t_outq.c_cc > 0)
- ttstart(tp);
- if (tp->t_outq.c_cc > DU_HIWAT)
- return;
- /* This happens briefly when the line shuts down. */
- if (ds == NULL) {
- DDEBUG(D_TRACE, "dutstart null ds (not an error)\n", 0, 0, 0);
- return;
- }
-
- /* If system is getting low on clists and we have something
- * running already, stop here. */
- if (cfreecount < CLISTRESERVE + ds->ds_mtu) {
- DDEBUG(D_TRACE, "clists = %d\n", cfreecount, 0, 0);
- ds->ds_flags &= ~DS_OACTIVE;
- /* If the free clist is empty, try to bring things back up to
- * the low water mark. Do our fair share. */
- if (cfreecount == 0) {
- DDEBUG(D_TRACE, "No clists, dumping some packets\n", 0, 0, 0);
- s = splimp();
- /* dequeue the pkts and hand back the mbufs */
- while (ds->ds_if.if_snd.ifq_len
- && cfreecount < CLISTRESERVE + ds->ds_mtu) {
- IF_DEQUEUE(&ds->ds_if.if_snd, m);
- IF_DROP(&ds->ds_if.if_snd);
- if (m)
- m_freem(m);
- }
- ds->ds_flags |= DS_OACTIVE;
- splx(s);
- }
- return;
- }
-
- /* Get a packet and send it to the interface. */
- DDEBUG(D_OUTPUT, "Getting a packet\n", 0, 0, 0);
- s = splimp();
- IF_DEQUEUE(&ds->ds_if.if_snd, m);
- if (m == NULL) {
- if (tp->t_outq.c_cc == 0) {
- ds->ds_flags &= ~DS_OACTIVE;
- ds->ds_timer = ds->ds_atimo;
- ds->ds_if.if_timer = DU_HZ;
- }
- splx(s);
- DDEBUG(D_OUTPUT, "null mbuf\n", 0, 0, 0);
- return;
- }
- flush = !(ds->ds_flags & DS_OACTIVE);
- ds->ds_flags |= DS_OACTIVE;
- ds->ds_timer = -1;
- ds->ds_if.if_timer = 0;
- splx(s);
- /* The extra FRAME_END will start up a new packet, and thus
- * will flush any accumulated garbage. We do this whenever
- * the line may have been idle for some time. */
- if (flush) {
- DDEBUG(D_OCHAR,"dutstart: Frame End\n", 0, 0, 0);
- (void) putc(FRAME_END, &tp->t_outq);
- ds->ds_cchs++; /* one for frame END */
- }
-
- while (m) {
- DDEBUG(D_OUTPUT, "M\n", 0, 0, 0);
- cp = mtod(m, u_char *);
- for (len = m->m_len, ds->ds_cchs += len; len > 0; ) {
- /* Find out how many bytes in the string we can
- * handle without doing something special. */
- nd = locc(FRAME_ESCAPE, len, cp);
- np = locc(FRAME_END, len, cp);
- n = len - MAX(nd, np);
- if (n) {
- /* Put n characters at once into the tty output queue. */
- if (b_to_q((char *)cp, n, &tp->t_outq))
- break;
- len -= n;
- cp += n;
- }
- /* If there are characters left in the mbuf, the first
- * one must be special -- put it out in a different form. */
- if (len) {
- DDEBUG(D_OCHAR,"dutstart: FRAME_ESC\n", 0, 0, 0);
- if (putc(FRAME_ESCAPE, &tp->t_outq))
- break;
- DDEBUG(D_OCHAR, "dutstart: *cp = x%02x\n", *cp, 0, 0);
- ds->ds_sesc++;
- if (putc(*cp == FRAME_ESCAPE ? TRANS_FRAME_ESCAPE :
- TRANS_FRAME_END, &tp->t_outq)) {
- (void)unputc(&tp->t_outq);
- break;
- }
- ds->ds_cchs += 2; /* one for ESC one for char */
- cp++;
- len--;
- }
- }
- MFREE(m, m2);
- m = m2;
- }
- DDEBUG(D_OPKT|D_OUTPUT, "ENDM\n", 0, 0, 0);
- if (putc(FRAME_END, &tp->t_outq)) {
- /* No room. Remove a char to make room and end the packet
- * normally. If you get many collisions (more than one or two
- * a day) you probably do not have enough clists. */
- (void)unputc(&tp->t_outq);
- (void)putc(FRAME_END, &tp->t_outq);
- ds->ds_if.if_collisions++;
- }
- else {
- ds->ds_if.if_opackets++;
- globdialstats.gds_opln++;
- ds->ds_cchs++; /* one for FRAME_END */
- }
- }
- }
-
-
-
- /*
- ** DU INTERFACE ROUTINES
- */
- duattach(net)
- int net;
- {
- static char du_names[(NDU / 10) + 1][4];
- register struct du_softc *ds;
- register int i;
-
- DDEBUG(D_TRACE, "duattach entered\n", 0, 0, 0);
- if (du_attached)
- return;
- du_attached = 1;
-
- /* Initialize the names (hard coded into dutioctl() also). */
- for (i = 0; i <= NDU / 10; i++) {
- du_names[i][0] = 'd';
- du_names[i][1] = 'u';
- du_names[i][2] = 'a' + i;
- du_names[i][3] = '\0';
- }
-
- /* Initialize the slots. */
- for (i = 0; i < NDU; i++) {
- ds = &du_softc[i];
- /* set up timer information -- wait for connection to time out. */
- ds->ds_atimo = DEFAULT_INACTIVITY_TIME/DU_HZ;
- ds->ds_wtimo = 12 * DU_HZ;
- ds->ds_timer = -1;
-
- /* Fill in if structure. */
- ds->ds_if.if_name = du_names[i / 10];
- ds->ds_if.if_unit = i % 10;
- ds->ds_if.if_mtu = ds->ds_mtu = DUMTU;
- ds->ds_if.if_flags = IFF_POINTOPOINT;
- ds->ds_if.if_ioctl = duioctl;
- ds->ds_if.if_output = duoutput;
- /* We need a larger queue because of the startup delay. */
- ds->ds_if.if_snd.ifq_maxlen = 2 * IFQ_MAXLEN;
- ds->ds_if.if_watchdog = dutimer;
- ds->ds_if.if_timer = 0;
- if_attach(&ds->ds_if);
- DDEBUG(D_TRACE, "duattach adding unit %s%d at 0x%x\n",
- ds->ds_if.if_name, ds->ds_if.if_unit, &ds->ds_if);
- }
- }
-
-
- /*
- ** Queue a packet. Start transmission if not active.
- */
- duoutput(ifp, m, dst)
- register struct ifnet *ifp;
- register struct mbuf *m;
- struct sockaddr *dst;
- {
- register struct du_softc *ds;
- register struct mbuf *tmpm;
- struct du_hdr leader;
- int s;
-
- DDEBUG(D_TRACE, "duoutput for \"%s%d\"\n", ifp->if_name, ifp->if_unit, 0);
- globdialstats.gds_ipup++;
-
- /* Check address family. */
- if (dst->sa_family != AF_INET) {
- printf("duoutput: \"%s%d\": AF %d not supported\n",
- ifp->if_name, ifp->if_unit, dst->sa_family);
- m_freem(m);
- return(EAFNOSUPPORT);
- }
-
- /* check family and build our leader. */
- bzero((caddr_t)&leader, sizeof leader);
- ds = &du_softc[DU_Index(ifp)];
- ds->ds_cprip++;
- leader.duh_type = DUT_IP;
- DDEBUG(D_OUTPUT, "dutoutput flags %x\n",ds->ds_flags, 0, 0);
-
- if (!(ds->ds_if.if_flags & IFF_UP)) {
- m_freem(m);
- return(EHOSTUNREACH);
- }
- if ((ds->ds_flags & DS_FAILCALL)) {
- m_freem(m);
- return(ENETDOWN);
- }
-
- if (!(ds->ds_flags & (DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL))) {
- if (!(ds->ds_flags & DS_ENABLECALL)) {
- m_freem(m);
- return(ENETDOWN);
- }
- /* Not waiting and not active -- eventually make unit
- * correspond to family. */
- if ((tmpm = m_pullup(m, sizeof(struct ip))) == NULL) {
- printf("m_pullup failed in duoutput\n");
- return(0);
- }
-
- /* get address of other end of p-to-p link */
- m = tmpm;
- if (dialupreq(mtod(m, struct ip *),
- #ifdef vax
- (struct sockaddr_in*)&ifp->if_addrlist->ifa_dstaddr,
- #else
- (struct sockaddr_in*)&ifp->if_dstaddr,
- #endif /* vax */
- ifp->if_name, ifp->if_unit, 1)) {
- m_freem(m);
- return(EHOSTUNREACH);
- }
-
- ds->ds_flags |= DS_LWAITING;
- ds->ds_timer = ds->ds_wtimo;
- ds->ds_if.if_timer = DU_HZ;
- }
-
- /* now queue */
- s = splimp();
- if (IF_QFULL(&ifp->if_snd)) {
- IF_DROP(&ifp->if_snd);
- splx(s);
- m_freem(m);
- ds->ds_if.if_oerrors++;
- return(ENOBUFS);
- }
- IF_ENQUEUE(&ifp->if_snd, m);
- splx(s);
-
- /* If line is up and no activity, start something */
- if ((ds->ds_flags & DS_LACTIVE) && !(ds->ds_flags & DS_OACTIVE)) {
- if (ds->ds_ttyp == NULL)
- panic("duoutput no tty");
-
- if (!(ds->ds_ttyp->t_state & TS_CARR_ON)) {
- DDEBUG(D_TRACE, "duoutput Carrier Loss.\n", 0, 0, 0);
- dutnetclose(ds);
- return(EHOSTUNREACH);
- }
- dutstart(ds->ds_ttyp);
- }
- return(0);
- }
-
-
- duinit(ds)
- register struct du_softc *ds;
- {
- #ifdef vax
- #ifdef ultrix
- #ifdef PRE_ULTRIX_3_0
- caddr_t km_alloc();
- #endif /* PRE_ULTRIX_3_0 */
- caddr_t p;
- #else
- struct mbuf *p;
- #endif /* ultrix */
- #else
- caddr_t kmem_alloc();
- caddr_t p;
- #endif /* vax */
-
- DDEBUG(D_TRACE, "duinit: ds %x\n", ds, 0, 0);
- if (ds->ds_buf == NULL) {
- #ifdef vax
- #ifdef ultrix
- #ifdef PRE_ULTRIX_3_0
- p = km_alloc(ds->ds_mtu);
- #else
- kmem_alloc(p, caddr_t, ds->ds_mtu, KM_DEVBUF);
- #endif /* PRE_ULTRIX_3_0 */
- #else
- MCLALLOC(p, 1);
- #endif /* ultrix */
- #else
- p = kmem_alloc(ds->ds_mtu);
- #endif /* vax */
-
- if (p == NULL) {
- printf("du%d: can't allocate buffer\n", ds - du_softc);
- ds->ds_if.if_flags &= ~IFF_UP;
- return(0);
- }
- ds->ds_buf = (char *)p;
- ds->ds_mp = ds->ds_buf;
- }
- return(1);
- }
-
-
-
- /*
- ** Monitor routine that records CPU state.
- */
- dialmonitor()
- {
- register struct du_softc *ds;
-
- for (ds = du_softc; ds < &du_softc[NDU]; ds++) {
- if (!(ds->ds_flags & DS_MONITORON) || ds->ds_ttyp == NULL)
- continue;
- if (ds->ds_ttyp->t_state & TS_BUSY)
- ds->ds_ctpbusy++;
- else
- ds->ds_ctpidle++;
- }
- timeout(dialmonitor, (caddr_t)NULL, DIAL_MONITORTIMEOUT);
- }
-
-
- /*
- ** IOCTL
- */
- duioctl(ifp, cmd, data, flags)
- register struct ifnet *ifp;
- int cmd;
- caddr_t data;
- int flags;
- {
- register struct sockaddr_in *sin;
- int s;
- int error;
- struct du_softc *ds;
-
- #ifdef vax
- sin = (struct sockaddr_in *)&((struct ifaddr *)data)->ifa_addr;
- #else /* vax */
- sin = (struct sockaddr_in *)data;
- #endif /* vax */
-
- DDEBUG(D_TRACE, "duioctl: \"%s%d\" cmd = 0x%x\n",
- ifp->if_name, ifp->if_unit, cmd);
- DDEBUG(D_TRACE, "duioctl: \"%s%d\" data = 0x%x\n",
- ifp->if_name, ifp->if_unit, data);
-
- error = 0;
- ds = &du_softc[DU_Index(ifp)];
- switch (cmd) {
-
- default:
- error = EINVAL;
-
- case SIOCSIFADDR:
- DDEBUG(D_IOCTL, "duioctl SIOCSIFADDR addr (0x%x)\n",
- sin->sin_addr.s_addr, 0, 0);
- #ifdef vax
- DDEBUG(D_IOCTL, "duioctl name %s addr (0x%x) dstaddr (0x%x)\n",
- ifp->if_name,
- ((struct sockaddr_in *)&ifp->if_addrlist->ifa_addr)->sin_addr.s_addr,
- ((struct sockaddr_in*)&ifp->if_addrlist->ifa_dstaddr)->sin_addr.s_addr);
- #endif /* vax */
-
- if (sin->sin_family != AF_INET) {
- error = EAFNOSUPPORT;
- break;
- }
- #ifdef vax
- ifp->if_flags |= IFF_UP;
- #else
- /* clear current route, set new address */
- if_rtinit(ifp, -1);
- ifp->if_addr = *(struct sockaddr *)data;
- ifp->if_net = in_netof(sin->sin_addr);
- ifp->if_flags |= IFF_UP | IFF_RUNNING;
-
- /* Set up routing entry. */
- if (!(ifp->if_flags & IFF_ROUTE)) {
- rtinit(&ifp->if_dstaddr, &ifp->if_addr,
- RTF_HOST|RTF_GATEWAY|RTF_UP);
- ifp->if_flags |= IFF_ROUTE;
- }
- #endif /* vax */
- ds->ds_flags |= DS_MONITORON | DS_ENABLECALL;
- timeout(dialmonitor, (caddr_t)NULL, DIAL_MONITORTIMEOUT);
- break;
-
- case SIOCSIFDSTADDR:
- if (sin->sin_family != AF_INET)
- error = EAFNOSUPPORT;
- break;
-
- case SIOCFAILCALL:
- s = splimp();
- /* Flush any waiting packets. */
- if (ds->ds_flags & DS_LWAITING) {
- while (ds->ds_if.if_snd.ifq_len) {
- register struct mbuf *m;
-
- IF_DEQUEUE(&ds->ds_if.if_snd,m);
- IF_DROP(&ds->ds_if.if_snd);
- if (m)
- m_freem(m);
- }
- ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN);
- ds->ds_flags |= DS_FAILCALL;
- ds->ds_timer = ds->ds_atimo;
- ds->ds_if.if_timer = DU_HZ;
- }
- splx(s);
- break;
-
- case SIOCSATIMEO:
- ds->ds_atimo = (u_long)GET_DATA(data) / DU_HZ;
- break;
-
- case SIOCGATIMEO:
- SET_DATA(data, (ds->ds_atimo * DU_HZ));
- break;
-
- case SIOCSWTIMEO:
- ds->ds_wtimo = (u_long)GET_DATA(data) / DU_HZ;
- break;
-
- case SIOCGWTIMEO:
- SET_DATA(data, (ds->ds_wtimo * DU_HZ));
- break;
-
- case SIOCSSOFTTIMER:
- s = splimp();
- ds->ds_timer = (u_long)GET_DATA(data);
- splx(s);
- break;
-
- case SIOCSSOFTFLAGS:
- s = splimp();
- ds->ds_flags = (int)GET_DATA(data);
- splx(s);
- break;
-
- case SIOCGSOFTFLAGS:
- s = splimp();
- SET_DATA(data, ds->ds_flags);
- splx(s);
- break;
-
- case SIOCGIPKTS:
- s = splimp();
- SET_DATA(data, ifp->if_ipackets);
- splx(s);
- break;
-
- case SIOCGOPKTS:
- s = splimp();
- SET_DATA(data, ifp->if_opackets);
- splx(s);
- break;
-
- case SIOCCLEARQ:
- s = splimp();
- /* dequeue the pkts and hand back the mbufs */
- while (ds->ds_if.if_snd.ifq_len) {
- struct mbuf *m;
-
- IF_DEQUEUE(&ds->ds_if.if_snd,m);
- IF_DROP(&ds->ds_if.if_snd);
- if (m)
- m_freem(m);
- }
- splx(s);
- break;
-
- case SIOCGIFMTU:
- SET_DATA(data, ds->ds_mtu);
- break;
-
- case SIOCSIFMTU:
- error = EBUSY; /* XXX */
- break;
-
- case SIOCBRINGUP:
- {
- struct ip ipfill;
- struct sockaddr_in sinfill;
-
- if (dialupreq(&ipfill, &sinfill, ifp->if_name, ifp->if_unit, 0)) {
- error = EHOSTUNREACH;
- break;
- }
- ds->ds_flags |= DS_LWAITING;
- ds->ds_timer = ds->ds_wtimo;
- ds->ds_if.if_timer = DU_HZ;
- /* If line is up and no activity, start something */
- if ((ds->ds_flags & DS_LACTIVE) && !(ds->ds_flags & DS_OACTIVE)) {
- if (ds->ds_ttyp == NULL)
- panic("duioctl no tty");
-
- if (!(ds->ds_ttyp->t_state & TS_CARR_ON)) {
- DDEBUG(D_TRACE, "duioctl Carrier Loss.\n", 0, 0, 0);
- dutnetclose(ds);
- error = EHOSTUNREACH;
- }
- dutstart(ds->ds_ttyp);
- }
- }
- }
- DDEBUG(D_IOCTL, "duioctl return(%d)\n", error, 0, 0);
- return(error);
- }
-
-
- /*
- ** Watchdog timer.
- ** Must figure out which interface timed out, since we only get a
- ** unit number.
- */
- dutimer(unit)
- int unit;
- {
- struct du_softc *ds;
- register int i;
- register int s;
-
- DDEBUG(D_TRACE, "dutimer: unit = %d\n", unit, 0, 0);
-
- if (unit < 0 || unit > 9)
- return;
- for (i = unit; i < NDU; i += 10) {
- if (i >= NDU)
- return;
-
- /* Test to see if this is the correct interface. */
- ds = &du_softc[i];
-
- DDEBUG(D_TIMER, "dutimer: unit %d, flags %x timer %d",
- i, (int)ds->ds_flags, (int)ds->ds_timer);
- DDEBUG(D_TIMER, "timer %d, if_timer %d, qlen %d\n",
- (int)ds->ds_if.if_timer, ds->ds_if.if_snd.ifq_len, 0);
-
- /* Is this the interface we want? */
- if (ds->ds_if.if_timer || ds->ds_timer <= 0)
- continue;
-
- /* just being cautious by setting up the interrupt priority */
- s = splimp();
- if (ds->ds_timer > 0 && --(ds->ds_timer) != 0) {
- /* Reset the interface timer */
- ds->ds_if.if_timer = DU_HZ;
- splx(s);
- continue;
- }
-
- /* If the call failed, allow new calls to be made. */
- if (ds->ds_flags & DS_FAILCALL)
- ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL);
-
- /* Trying to get a line - timeout. */
- if (ds->ds_flags & DS_LWAITING) {
- /* we never had a line, just tidy the net */
- DDEBUG(D_TRACE, "dutimer: unit %d - we never had a line.\n",
- i, 0, 0);
- dutnetclose(ds);
- ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL);
- }
-
- /* Is the line to be shutdown? */
- if (ds->ds_flags & DS_LDOWN) {
- DDEBUG(D_TRACE, "dutimer: unit %d - shutdown net and line.\n",
- i, 0, 0);
- dutnetclose(ds);
- if (ds->ds_ttyp)
- /* just being careful */
- dutclose(ds->ds_ttyp);
- ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL);
- }
-
- /* inactivity timer just went off - shutdown the line */
- if (ds->ds_flags & DS_LACTIVE) {
- /* mistaken? */
- if (ds->ds_flags & DS_OACTIVE)
- ds->ds_timer = -1;
- else {
- DDEBUG(D_TRACE, "dutimer: unit %d - bringing down line.\n",
- i, 0, 0);
- dutnetclose(ds);
- if (ds->ds_ttyp)
- dutclose(ds->ds_ttyp);
- }
- }
- splx(s);
- }
- }
-
-
- #ifndef vax
- /*
- ** locc appears to only be in 4.3 for vaxen
- */
- int
- locc(mask, size, cp)
- register u_char mask;
- u_int size;
- register u_char *cp;
- {
- register u_char *end;
-
- for (end = &cp[size]; cp < end && *cp != mask; cp++)
- ;
- return(end - cp);
- }
- #endif /* vax*/
-
- #endif /* NDU > 0 */
-