This is if_du.c in view mode; [Download] [Up]
/* ** 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 */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.