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.