xref: /csrg-svn/sys/vax/if/if_dp.c (revision 48964)
145163Ssklower /*
245163Ssklower  * Copyright (c) 1990 Regents of the University of California.
345163Ssklower  * All rights reserved.
445163Ssklower  *
545163Ssklower  * %sccs.include.redist.c%
645163Ssklower  *
7*48964Ssklower  *	@(#)if_dp.c	7.8 (Berkeley) 05/02/91
845163Ssklower  */
945163Ssklower 
1045163Ssklower #include "dp.h"
1145163Ssklower #if NDP > 0
1245163Ssklower 
1345163Ssklower /*
1445163Ssklower  * DPV-11 device driver, X.25 version
1545163Ssklower  *
1645163Ssklower  * Derived from dmc-11 driver:
1745163Ssklower  *
1845163Ssklower  *	Bill Nesheim
1945163Ssklower  *	Cornell University
2045163Ssklower  *
2145163Ssklower  *	Lou Salkind
2245163Ssklower  *	New York University
2345163Ssklower  */
2445163Ssklower 
2545163Ssklower /* #define DEBUG	/* for base table dump on fatal error */
2645163Ssklower 
2745801Sbostic #include "../include/pte.h"
2845163Ssklower 
2945801Sbostic #include "sys/param.h"
3045801Sbostic #include "sys/systm.h"
3145801Sbostic #include "sys/mbuf.h"
3245801Sbostic #include "sys/buf.h"
3345801Sbostic #include "sys/ioctl.h"		/* must precede tty.h */
3445801Sbostic #include "sys/protosw.h"
3545801Sbostic #include "sys/socket.h"
3645801Sbostic #include "sys/socketvar.h"
3745801Sbostic #include "sys/syslog.h"
3845801Sbostic #include "sys/vmmac.h"
3945801Sbostic #include "sys/errno.h"
4045801Sbostic #include "sys/time.h"
4145801Sbostic #include "sys/kernel.h"
4245163Ssklower 
4345801Sbostic #include "net/if.h"
44*48964Ssklower #include "net/if_types.h"
4545801Sbostic #include "net/netisr.h"
4645801Sbostic #include "net/route.h"
4745163Ssklower 
4845801Sbostic #include "../include/cpu.h"
4945801Sbostic #include "../include/mtpr.h"
5045166Ssklower 
5145228Ssklower #define	dzdevice dpdevice
5245801Sbostic #include "../uba/pdma.h"
5345801Sbostic #include "../uba/ubavar.h"
5445163Ssklower 
5545801Sbostic #include "netccitt/x25.h"
5645801Sbostic #include "netccitt/pk.h"
5745801Sbostic #include "netccitt/pk_var.h"
5845166Ssklower 
5945163Ssklower #include "if_dpreg.h"
6045163Ssklower 
6145163Ssklower /*
6245163Ssklower  * Driver information for auto-configuration stuff.
6345163Ssklower  */
6445163Ssklower int	dpprobe(), dpattach(), dpinit(), dpioctl(), dprint(), dpxint();
6545228Ssklower int	dpoutput(), dpreset(), dptimeout(), dpstart(), x25_ifoutput(), dptestoutput();
6645163Ssklower 
6745163Ssklower struct	uba_device *dpinfo[NDP];
6845163Ssklower 
6945163Ssklower u_short	dpstd[] = { 0 };
7045163Ssklower struct	uba_driver dpdriver =
7145163Ssklower 	{ dpprobe, 0, dpattach, 0, dpstd, "dp", dpinfo };
7245163Ssklower 
7345163Ssklower /*
7445163Ssklower  * Pdma structures for fast interrupts.
7545163Ssklower  */
7645163Ssklower struct	pdma dppdma[2*NDP];
7745163Ssklower 
7845163Ssklower /*
7945163Ssklower  * DP software status per interface.
8045163Ssklower  *
8145163Ssklower  * Each interface is referenced by a network interface structure,
8245163Ssklower  * dp_if, which the routing code uses to locate the interface.
8345163Ssklower  * This structure contains the output queue for the interface, its address, ...
8445163Ssklower  */
8545163Ssklower struct dp_softc {
8645163Ssklower 	struct	ifnet dp_if;		/* network-visible interface */
8745228Ssklower 	int	dp_ipl;
8845236Ssklower 	struct	dpdevice *dp_addr;	/* dpcsr address */
8945163Ssklower 	short	dp_iused;		/* input buffers given to DP */
9045163Ssklower 	short	dp_flags;		/* flags */
9145228Ssklower #define DPF_RUNNING	0x01		/* device initialized */
9245228Ssklower #define DPF_ONLINE	0x02		/* device running (had a RDYO) */
9345228Ssklower #define DPF_RESTART	0x04		/* software restart in progress */
9445228Ssklower #define DPF_FLUSH	0x08		/* had a ROVR, flush ipkt when done */
9545163Ssklower 	short	dp_ostate;		/* restarting, etc. */
9645163Ssklower 	short	dp_istate;		/* not sure this is necessary */
9745163Ssklower #define DPS_IDLE	0
9845163Ssklower #define DPS_RESTART	1
9945163Ssklower #define DPS_ACTIVE	2
10045163Ssklower #define DPS_XEM		3		/* transmitting CRC, etc. */
10145289Ssklower 	short	dp_olen;		/* length of last packet sent */
10245289Ssklower 	short	dp_ilen;		/* length of last packet recvd */
10345163Ssklower 	char	dp_obuf[DP_MTU+8];
10445166Ssklower 	char	dp_ibuf[DP_MTU+8];
10545163Ssklower } dp_softc[NDP];
10645163Ssklower 
10745289Ssklower /*
10845289Ssklower  * Debug info
10945289Ssklower  */
11045289Ssklower struct	dpstat {
11145289Ssklower 	long	start;
11245289Ssklower 	long	nohdr;
11345289Ssklower 	long	init;
11445289Ssklower 	long	rint;
11545289Ssklower 	long	xint;
11645289Ssklower 	long	reset;
11745289Ssklower 	long	ioctl;
11845289Ssklower 	long	down;
11945289Ssklower 	long	mchange;
12045289Ssklower 	long	timeout;
12145289Ssklower 	long	rsm;
12245289Ssklower 	long	rem;
12345289Ssklower 	long	remchr;
12445289Ssklower 	long	rga;
12545289Ssklower 	long	xem;
12645289Ssklower 	long	rovr;
12745289Ssklower } dpstat;
12845289Ssklower 
12945289Ssklower short dp_ilb = 0;
130*48964Ssklower short dp_log = 0;
13145289Ssklower 
13245289Ssklower #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
13345289Ssklower int dp_sizes[] = {
13445289Ssklower 	sizeof(dp_softc[0]), sizeof(struct ifnet),
13545289Ssklower 	_offsetof(struct dp_softc, dp_obuf[0]),
13645289Ssklower 	_offsetof(struct dp_softc, dp_ibuf[0]),
13745289Ssklower 	};
13845289Ssklower 
13945163Ssklower dpprobe(reg, ui)
14045163Ssklower 	caddr_t reg;
14145163Ssklower 	struct	uba_device *ui;
14245163Ssklower {
14345163Ssklower 	register int br, cvec;
14445163Ssklower 	register struct dpdevice *addr = (struct dpdevice *)reg;
14545236Ssklower 	register int unit = ui->ui_unit;
14645163Ssklower 
14745163Ssklower #ifdef lint
14845163Ssklower 	br = 0; cvec = br; br = cvec;
14945163Ssklower 	dprint(0); dpxint(0);
15045163Ssklower #endif
15145228Ssklower 	(void) spl6();
15245163Ssklower 	addr->dpclr = DP_CLR;
15345163Ssklower 	addr->dpclr = DP_XIE|DP_XE;
15445163Ssklower 	DELAY(100000);
15545236Ssklower 	dp_softc[unit].dp_ipl = br = qbgetpri();
15645236Ssklower 	dp_softc[unit].dp_addr = addr;
15745163Ssklower 	addr->dpclr = 0;
15845228Ssklower 	if (cvec && cvec != 0x200){
15945228Ssklower 		cvec -= 4;
16045228Ssklower 	}
16145163Ssklower 	return (1);
16245163Ssklower }
16345163Ssklower 
16445163Ssklower /*
16545163Ssklower  * Interface exists: make available by filling in network interface
16645163Ssklower  * record.  System will initialize the interface when it is ready
16745163Ssklower  * to accept packets.
16845163Ssklower  */
16945163Ssklower dpattach(ui)
17045163Ssklower 	register struct uba_device *ui;
17145163Ssklower {
17245163Ssklower 	register struct dp_softc *dp = &dp_softc[ui->ui_unit];
17345163Ssklower 
17445163Ssklower 	dp->dp_if.if_unit = ui->ui_unit;
17545163Ssklower 	dp->dp_if.if_name = "dp";
17645163Ssklower 	dp->dp_if.if_mtu = DP_MTU;
17745163Ssklower 	dp->dp_if.if_init = dpinit;
17845163Ssklower 	dp->dp_if.if_output = x25_ifoutput;
179*48964Ssklower 	dp->dp_if.if_type = IFT_X25;
180*48964Ssklower 	dp->dp_if.if_hdrlen = 5;
181*48964Ssklower 	dp->dp_if.if_addrlen = 8;
18245163Ssklower 	dp->dp_if.if_start = dpstart;
18345163Ssklower 	dp->dp_if.if_ioctl = dpioctl;
18445163Ssklower 	dp->dp_if.if_reset = dpreset;
18545163Ssklower 	dp->dp_if.if_watchdog = dptimeout;
18645228Ssklower 	dp->dp_if.if_flags = 0;
18745163Ssklower 	if_attach(&dp->dp_if);
18845163Ssklower }
18945163Ssklower 
19045163Ssklower /*
19145163Ssklower  * Reset of interface after UNIBUS reset.
19245163Ssklower  * If interface is on specified UBA, reset its state.
19345163Ssklower  */
19445163Ssklower dpreset(unit, uban)
19545163Ssklower 	int unit, uban;
19645163Ssklower {
19745163Ssklower 	register struct uba_device *ui;
19845163Ssklower 	register struct dp_softc *dp = &dp_softc[unit];
19945163Ssklower 	register struct dpdevice *addr;
20045163Ssklower 
20145228Ssklower 	dpstat.reset++;
20245163Ssklower 	if (unit >= NDP || (ui = dpinfo[unit]) == 0 || ui->ui_alive == 0 ||
20345163Ssklower 	    ui->ui_ubanum != uban)
20445163Ssklower 		return;
20545236Ssklower 	dpdown(unit);
20645236Ssklower 	dpinit(unit);
20745163Ssklower 	printf(" dp%d", unit);
20845163Ssklower }
20945163Ssklower 
21045163Ssklower /*
21145163Ssklower  * Initialization of interface.
21245163Ssklower  */
21345163Ssklower dpinit(unit)
21445163Ssklower 	int unit;
21545163Ssklower {
21645163Ssklower 	register struct dp_softc *dp = &dp_softc[unit];
21745163Ssklower 	register struct dpdevice *addr;
21845228Ssklower 	register struct ifaddr *ifa;
21945228Ssklower 	register struct pdma *pdp = &dppdma[unit*2];
22045228Ssklower 	int base, s;
22145163Ssklower 
22245228Ssklower 	dpstat.init++;
22345163Ssklower 	/*
22445163Ssklower 	 * Check to see that an address has been set.
22545163Ssklower 	 */
22645228Ssklower 	for (ifa = dp->dp_if.if_addrlist; ifa; ifa = ifa->ifa_next)
22745163Ssklower 		if (ifa->ifa_addr->sa_family != AF_LINK)
22845163Ssklower 			break;
22945163Ssklower 	if (ifa == (struct ifaddr *) 0)
23045163Ssklower 		return;
23145163Ssklower 
23245236Ssklower 	addr = dp->dp_addr;
23345228Ssklower 	s = splimp();
23445163Ssklower 	dp->dp_iused = 0;
23545163Ssklower 	dp->dp_istate = dp->dp_ostate = DPS_IDLE;
23645228Ssklower 	dp->dp_if.if_flags |= IFF_RUNNING;
23745228Ssklower 	dp->dp_if.if_flags &= ~IFF_OACTIVE;
23845228Ssklower 
23945228Ssklower 	pdp->p_addr = addr;
24045228Ssklower 	pdp->p_fcn = dpxint;
24145228Ssklower 	pdp->p_mem = pdp->p_end = dp->dp_obuf;
24245228Ssklower 	pdp++;
24345228Ssklower 	pdp->p_addr = addr;
24445228Ssklower 	pdp->p_fcn = dprint;
24545228Ssklower 	/* force initial interrupt to come to dprint */
24645228Ssklower 	pdp->p_mem = pdp->p_end = dp->dp_ibuf + DP_MTU + 8;
24745228Ssklower 
24845228Ssklower 	addr->dpclr = DP_CLR;
24945289Ssklower 	DELAY(5000);
25045237Ssklower 	/* DP_ATA = 0, DP_CHRM = 0, DP_SSLM = 1, (enable aborts),
25145237Ssklower 			    CRC = CCIIT, initially all ones, 2nd addr = 0 */
25245237Ssklower 	addr->dpsar = DP_SSLM | DP_IDLE;
25345289Ssklower 	addr->dpclr = DP_XE | dp_ilb;
25445289Ssklower 	addr->dptdsr = DP_XSM;
25545237Ssklower 	/* enable receiver, receive interrupt, DTR, RTS */
25645228Ssklower 	addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
25745228Ssklower 	dpstart(&dp->dp_if);
25845163Ssklower 	splx(s);
25945163Ssklower }
26045163Ssklower 
26145163Ssklower /*
26245163Ssklower  * Start output on interface.  Get another datagram
26345163Ssklower  * to send from the interface queue and map it to
26445163Ssklower  * the interface before starting output.
26545163Ssklower  *
26645163Ssklower  */
26745163Ssklower dpstart(ifp)
26845163Ssklower 	struct ifnet *ifp;
26945163Ssklower {
27045228Ssklower 	int s, unit = ifp->if_unit, error = 0, len;
27145163Ssklower 	register struct dp_softc *dp = &dp_softc[unit];
27245237Ssklower 	register struct dpdevice *addr = dp->dp_addr;
27345163Ssklower 	register struct mbuf *m;
27445163Ssklower 	register char *cp;
27545163Ssklower 	char *cplim;
27645163Ssklower 
27745163Ssklower 	/*
27845163Ssklower 	 * If already doing output, go away and depend on transmit
27945163Ssklower 	 * complete or error.
28045163Ssklower 	 */
28145228Ssklower 	dpstat.start++;
28245236Ssklower 	if ((dp->dp_if.if_flags & IFF_OACTIVE) ||
28345289Ssklower 	    (dp->dp_if.if_flags & IFF_RUNNING) == 0)
28445228Ssklower 		goto out;
28545163Ssklower 	IF_DEQUEUE(&dp->dp_if.if_snd, m);
28645163Ssklower 	if (m == 0)
28745228Ssklower 		goto out;
28845228Ssklower 	dp->dp_if.if_collisions++;
28945228Ssklower 	if (m->m_flags & M_PKTHDR)
29045228Ssklower 		len = m->m_pkthdr.len;
29145228Ssklower 	else {
29245228Ssklower 		struct mbuf *m0 = m;
29345228Ssklower 		for (len = 0; m; m = m->m_next)
29445228Ssklower 			len += m->m_len;
29545228Ssklower 		m = m0;
29645228Ssklower 		dpstat.nohdr++;
29745228Ssklower 	}
29845289Ssklower 	if (len < 2)
29945228Ssklower 		goto out;
30045228Ssklower 	if (len > DP_MTU) {
30145228Ssklower 		error = EINVAL;
30245228Ssklower 		goto out;
30345228Ssklower 	}
30445289Ssklower 	dppdma[2*unit].p_mem = cp = dp->dp_obuf;
30545163Ssklower 	while (m) {
30645163Ssklower 		struct mbuf *n;
30745163Ssklower 		bcopy(mtod(m, caddr_t), (caddr_t)cp, m->m_len);
30845163Ssklower 		cp += m->m_len;
30945163Ssklower 		MFREE(m, n); m = n;
31045163Ssklower 	}
31145289Ssklower 	dppdma[2*unit].p_end = cp - 1;
31245163Ssklower 	dp->dp_if.if_flags |= IFF_OACTIVE;
31345163Ssklower 	dp->dp_ostate = DPS_ACTIVE;
31445228Ssklower 	dp->dp_if.if_collisions--;
31545289Ssklower 	dp->dp_olen = len;
31645289Ssklower 	if (dp_log) {
31745289Ssklower 		register u_char *p = (u_char *)dp->dp_obuf;
31845289Ssklower 		log(LOG_DEBUG, "dpoutput(%d):%x %x %x %x %x\n",
31945289Ssklower 			len, p[0], p[1], p[2], p[3], p[4]);
32045289Ssklower 	}
32145237Ssklower 	addr->dpsar = DP_SSLM | DP_IDLE;
32245237Ssklower 	addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
32345289Ssklower 	addr->dpclr = DP_XIE | DP_XE | dp_ilb;
32445289Ssklower 	addr->dptdsr = DP_XSM;
32545228Ssklower out:
32645228Ssklower 	return (error);
32745163Ssklower }
32845163Ssklower /*
32945163Ssklower  * Receive done or error interrupt
33045163Ssklower  */
33145163Ssklower dprint(unit, pdma, addr)
33245163Ssklower register struct pdma *pdma;
33345163Ssklower register struct dpdevice *addr;
33445163Ssklower {
33545166Ssklower 	register struct dp_softc *dp = &dp_softc[unit];
33645237Ssklower 	short rdsr = addr->dprdsr, rcsr = pdma->p_arg;
33745163Ssklower 
33845228Ssklower 	dpstat.rint++;
33945228Ssklower 	splx(dp->dp_ipl);
34045237Ssklower 	if (rdsr & DP_RGA) {
34145237Ssklower 		/* DP_ATA = 0, DP_CHRM = 0, DP_SSLM = 1, (enable aborts),
34245237Ssklower 			    CRC = CCIIT, initially all ones, 2nd addr = 0 */
34345237Ssklower 		addr->dpsar = DP_SSLM | DP_IDLE;
34445237Ssklower 		addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
34545237Ssklower 		dpstat.rga++;
34645237Ssklower 		return;
34745237Ssklower 	}
34845166Ssklower 	if (rdsr & DP_RSM) { /* Received Start of Message */
34945237Ssklower 		dpstat.rsm++;
35045237Ssklower 		pdma->p_mem = dp->dp_ibuf;
35145237Ssklower 		if (rcsr & DP_RDR) {
35245237Ssklower 		    dp->dp_ibuf[0] = rdsr & DP_RBUF;
35345237Ssklower 		    pdma->p_mem++;
35445237Ssklower 		}
35545166Ssklower 		dp->dp_flags &= ~DPF_FLUSH;
35645163Ssklower 		return;
35745163Ssklower 	}
35845166Ssklower 	if (rdsr & DP_REM) { /* Received End of Message */
35945237Ssklower 		dpstat.rem++;
36045289Ssklower 		if (rcsr & DP_RDR) {
36145289Ssklower 		    *(pdma->p_mem++) = rdsr;
36245289Ssklower 		    dpstat.remchr++;
36345289Ssklower 		}
36445289Ssklower 		dp->dp_ilen = pdma->p_mem - dp->dp_ibuf;
36545166Ssklower 		if (rdsr & DP_REC || dp->dp_flags & DPF_FLUSH) {
36645166Ssklower 			dp->dp_if.if_ierrors++;
36745228Ssklower 		} else
36845289Ssklower 			dpinput(&dp->dp_if, dp->dp_ilen, dp->dp_ibuf);
36945228Ssklower 		pdma->p_mem = pdma->p_end;
37045228Ssklower 		dp->dp_flags &= ~ DPF_FLUSH;
37145228Ssklower 		return;
37245228Ssklower 	}
37345228Ssklower 	if (rdsr & DP_ROVR) {
37445289Ssklower 		dpstat.rovr++;
37545228Ssklower 		dp->dp_flags |= DPF_FLUSH;
37645228Ssklower 		return;
37745228Ssklower 	}
37845228Ssklower 	if (rcsr & DP_MSC) {
37945228Ssklower 		dpstat.mchange++;
38045228Ssklower 		if (0 == (rcsr & DP_DSR)) {
38145228Ssklower 			log(LOG_DEBUG, "dp%d: lost modem\n", unit);
38245237Ssklower 			/*dpdown(unit);*/
38345163Ssklower 		}
38445163Ssklower 		return;
38545163Ssklower 	}
38645163Ssklower 	dp->dp_flags |= DPF_FLUSH;
38745163Ssklower 	if (pdma->p_mem != pdma->p_end)
38845289Ssklower 		log(LOG_DEBUG, "dp%d: unexplained receiver interrupt\n", unit);
38945163Ssklower }
39045163Ssklower /*
39145163Ssklower  * Transmit complete or error interrupt
39245163Ssklower  */
39345163Ssklower dpxint(unit, pdma, addr)
39445163Ssklower register struct pdma *pdma;
39545163Ssklower register struct dpdevice *addr;
39645163Ssklower {
39745166Ssklower 	register struct dp_softc *dp = &dp_softc[unit];
39845228Ssklower 	int s;
39945163Ssklower 
40045228Ssklower 	splx(dp->dp_ipl);
40145228Ssklower 	dpstat.xint++;
40245163Ssklower 	if (addr->dptdsr & DP_XERR) {
40345289Ssklower 		log(LOG_DEBUG, "if_dp%d: data late\n", unit);
40445163Ssklower 	restart:
40545163Ssklower 		pdma->p_mem = dp->dp_obuf;
40645163Ssklower 		addr->dptdsr = DP_XSM;
40745228Ssklower 		dp->dp_if.if_oerrors++;
40845163Ssklower 		return;
40945163Ssklower 	}
41045163Ssklower 	switch (dp->dp_ostate) {
41145163Ssklower 
41245163Ssklower 	case DPS_ACTIVE:
41345163Ssklower 		if (pdma->p_mem != pdma->p_end) {
41445289Ssklower 			log(LOG_DEBUG, "if_dp%d: misc error in dpxint\n", unit);
41545163Ssklower 			goto restart;
41645163Ssklower 		}
41745289Ssklower 		addr->dpsar = DP_IDLE|DP_SSLM;
41845289Ssklower 		addr->dpclr = DP_XE | DP_XIE | dp_ilb;
41945289Ssklower 		addr->dptdsr = DP_XEM | (0xff & pdma->p_mem[0]);
42045289Ssklower 		addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
42145163Ssklower 		dp->dp_ostate = DPS_XEM;
42245163Ssklower 		break;
42345163Ssklower 
42445163Ssklower 	case DPS_XEM:
42545289Ssklower 		dpstat.xem++;
42645228Ssklower 		dp->dp_if.if_opackets++;
42745289Ssklower 		dp->dp_ostate = DPS_IDLE;
42845163Ssklower 		dp->dp_if.if_flags &= ~IFF_OACTIVE;
42945163Ssklower 		if (dp->dp_if.if_snd.ifq_len)
43045163Ssklower 			dpstart(&dp->dp_if);
43145163Ssklower 		else {
43245289Ssklower 			addr->dpsar = DP_IDLE|DP_SSLM;
43345289Ssklower 			addr->dpclr = DP_XE | dp_ilb;
43445289Ssklower 			addr->dptdsr = DP_XSM;
43545289Ssklower 			addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR|DP_RTS;
43645163Ssklower 		}
43745163Ssklower 		break;
43845163Ssklower 
43945163Ssklower 	default:
44045289Ssklower 		log(LOG_DEBUG, "if_dp%d: impossible state in dpxint\n");
44145163Ssklower 	}
44245163Ssklower }
44345163Ssklower /*
44445163Ssklower  * Routine to copy from device buffer into mbufs.
44545163Ssklower  *
44645163Ssklower  * Warning: This makes the fairly safe assumption that
44745163Ssklower  * mbufs have even lengths.
44845163Ssklower  */
44945163Ssklower struct mbuf *
45045163Ssklower dpget(rxbuf, totlen, off, ifp)
45145163Ssklower 	caddr_t rxbuf;
45245163Ssklower 	int totlen, off;
45345163Ssklower 	struct ifnet *ifp;
45445163Ssklower {
45545163Ssklower 	register caddr_t cp;
45645163Ssklower 	register struct mbuf *m;
45745163Ssklower 	struct mbuf *top = 0, **mp = &top;
45845163Ssklower 	int len;
45945163Ssklower 	caddr_t packet_end;
46045163Ssklower 
46145163Ssklower 	cp = rxbuf;
46245163Ssklower 	packet_end = cp + totlen;
46345163Ssklower 	if (off) {
46445163Ssklower 		off += 2 * sizeof(u_short);
46545163Ssklower 		totlen -= 2 *sizeof(u_short);
46645163Ssklower 		cp = rxbuf + off;
46745163Ssklower 	}
46845163Ssklower 
46945163Ssklower 	MGETHDR(m, M_DONTWAIT, MT_DATA);
47045163Ssklower 	if (m == 0)
47145163Ssklower 		return (0);
47245163Ssklower 	m->m_pkthdr.rcvif = ifp;
47345163Ssklower 	m->m_pkthdr.len = totlen;
47445163Ssklower 	m->m_len = MHLEN;
47545163Ssklower 
47645163Ssklower 	while (totlen > 0) {
47745163Ssklower 		if (top) {
47845163Ssklower 			MGET(m, M_DONTWAIT, MT_DATA);
47945163Ssklower 			if (m == 0) {
48045163Ssklower 				m_freem(top);
48145163Ssklower 				return (0);
48245163Ssklower 			}
48345163Ssklower 			m->m_len = MLEN;
48445163Ssklower 		}
48545163Ssklower 		len = min(totlen, (packet_end - cp));
48645163Ssklower 		if (len >= MINCLSIZE) {
48745163Ssklower 			MCLGET(m, M_DONTWAIT);
48845163Ssklower 			if (m->m_flags & M_EXT)
48945163Ssklower 				m->m_len = len = min(len, MCLBYTES);
49045163Ssklower 			else
49145163Ssklower 				len = m->m_len;
49245163Ssklower 		} else {
49345163Ssklower 			/*
49445163Ssklower 			 * Place initial small packet/header at end of mbuf.
49545163Ssklower 			 */
49645163Ssklower 			if (len < m->m_len) {
49745163Ssklower 				if (top == 0 && len + max_linkhdr <= m->m_len)
49845163Ssklower 					m->m_data += max_linkhdr;
49945163Ssklower 				m->m_len = len;
50045163Ssklower 			} else
50145163Ssklower 				len = m->m_len;
50245163Ssklower 		}
50345163Ssklower 		bcopy(cp, mtod(m, caddr_t), (u_int)len);
50445163Ssklower 		*mp = m;
50545163Ssklower 		mp = &m->m_next;
50645163Ssklower 		totlen -= len;
50745163Ssklower 		cp += len;
50845163Ssklower 		if (cp == packet_end)
50945163Ssklower 			cp = rxbuf;
51045163Ssklower 	}
51145163Ssklower 	return (top);
51245163Ssklower }
51345163Ssklower 
51445228Ssklower dpinput(ifp, len, buffer)
51545228Ssklower register struct ifnet *ifp;
51645163Ssklower caddr_t buffer;
51745163Ssklower {
51845163Ssklower 	register struct ifqueue *inq;
51945163Ssklower 	register struct mbuf *m;
52045228Ssklower 	extern struct ifqueue hdintrq, ipintrq;
52145289Ssklower 	int isr;
52245163Ssklower 
52345228Ssklower 	ifp->if_ipackets++;
52445289Ssklower 	if (dp_log) {
52545289Ssklower 		register u_char *p = (u_char *)buffer;
52645289Ssklower 		log(LOG_DEBUG, "dpinput(%d):%x %x %x %x %x\n",
52745289Ssklower 			len, p[0], p[1], p[2], p[3], p[4]);
52845289Ssklower 	}
52945289Ssklower 
53045228Ssklower     {
53145228Ssklower 	register struct ifaddr *ifa = ifp->if_addrlist;
53245228Ssklower 	register u_char *cp = (u_char *)buffer;
53345228Ssklower 
53445228Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
53545228Ssklower 		if (ifa->ifa_addr->sa_family != AF_LINK)
53645228Ssklower 			break;
53745228Ssklower 	if (cp[0] == 0xff && cp[1] == 0x3) {
53845228Ssklower 		/* This is a UI HDLC Packet, so we'll assume PPP
53945228Ssklower 		   protocol.  for now, IP only. */
54045228Ssklower 		buffer += 4;
54145228Ssklower 		len -= 4;
54245228Ssklower 		inq = &ipintrq;
54345289Ssklower 		isr = NETISR_IP;
54445228Ssklower 	} else {
54545228Ssklower 		inq = &hdintrq;
54645289Ssklower 		isr = NETISR_CCITT;
54745228Ssklower 	}
54845228Ssklower     }
54945228Ssklower 	if (len <= 0)
55045163Ssklower 		return;
55145163Ssklower 
55245163Ssklower 	m = dpget(buffer, len , 0, ifp);
55345163Ssklower 	if (m == 0)
55445163Ssklower 		return;
55545163Ssklower 
55645163Ssklower 	if(IF_QFULL(inq)) {
55745163Ssklower 		IF_DROP(inq);
55845163Ssklower 		m_freem(m);
55945163Ssklower 	} else {
56045163Ssklower 		IF_ENQUEUE(inq, m);
56145289Ssklower 		schednetisr(isr);
56245163Ssklower 	}
56345163Ssklower }
56445163Ssklower 
56545163Ssklower /*
56645163Ssklower  * Process an ioctl request.
56745163Ssklower  */
56845163Ssklower dpioctl(ifp, cmd, data)
56945163Ssklower 	register struct ifnet *ifp;
57045163Ssklower 	int cmd;
57145163Ssklower 	caddr_t data;
57245163Ssklower {
57345163Ssklower 	register struct ifaddr *ifa = (struct ifaddr *)data;
57445163Ssklower 	int s = splimp(), error = 0;
57545166Ssklower 	struct dp_softc *dp = &dp_softc[ifp->if_unit];
57645163Ssklower 
57745228Ssklower 	dpstat.ioctl++;
57845163Ssklower 	switch (cmd) {
57945163Ssklower 
58045163Ssklower 	case SIOCSIFADDR:
58145163Ssklower 		ifp->if_flags |= IFF_UP;
58245163Ssklower 		switch (ifa->ifa_addr->sa_family) {
58345228Ssklower 		case AF_INET:
58445228Ssklower 			ifp->if_output = dptestoutput;
58545163Ssklower 		default:
58645163Ssklower 			dpinit(ifp->if_unit);
58745163Ssklower 			break;
58845163Ssklower 		}
58945163Ssklower 		break;
59045228Ssklower #ifdef CCITT
59145228Ssklower 	case SIOCSIFCONF_X25:
59245228Ssklower 		ifp->if_flags |= IFF_UP;
59345228Ssklower 		ifp->if_output = x25_ifoutput;
59445228Ssklower 		error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
59545228Ssklower 		if (error == 0)
59645228Ssklower 			dpinit(ifp->if_unit);
59745228Ssklower 		break;
59845228Ssklower #endif
59945163Ssklower 
60045228Ssklower 	case SIOCSIFFLAGS:
60145228Ssklower 		if ((ifp->if_flags & IFF_UP) == 0 &&
60245228Ssklower 		    (ifp->if_flags & IFF_RUNNING))
60345228Ssklower 			dpdown(ifp->if_unit);
60445228Ssklower 		else if (ifp->if_flags & IFF_UP &&
60545228Ssklower 		    (ifp->if_flags & IFF_RUNNING) == 0)
60645228Ssklower 			dpinit(ifp->if_unit);
60745228Ssklower 		break;
60845163Ssklower 
60945228Ssklower 
61045163Ssklower 	default:
61145163Ssklower 		error = EINVAL;
61245163Ssklower 	}
61345163Ssklower 	splx(s);
61445163Ssklower 	return (error);
61545163Ssklower }
61645163Ssklower /*
61745163Ssklower  * Reset a device and mark down.
61845163Ssklower  * Flush output queue and drop queue limit.
61945163Ssklower  */
62045163Ssklower dpdown(unit)
62145236Ssklower int unit;
62245163Ssklower {
62345236Ssklower 
62445163Ssklower 	register struct dp_softc *dp = &dp_softc[unit];
62545236Ssklower 	register struct dpdevice *addr = dp->dp_addr;
62645163Ssklower 
62745228Ssklower 	dpstat.down++;
62845163Ssklower 	if_qflush(&dp->dp_if.if_snd);
62945236Ssklower 	dp->dp_flags = 0;
63045236Ssklower 	dp->dp_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
63145236Ssklower 
63245236Ssklower 	addr->dpclr = DP_CLR;
63345236Ssklower 	DELAY(1000);
63445236Ssklower 	addr->dpsar = 0;
63545236Ssklower 	addr->dprcsr = 0;
63645163Ssklower }
63745163Ssklower 
63845163Ssklower /*
63945163Ssklower  * Watchdog timeout to see that transmitted packets don't
64045163Ssklower  * lose interrupts.  The device has to be online (the first
64145163Ssklower  * transmission may block until the other side comes up).
64245163Ssklower  */
64345163Ssklower dptimeout(unit)
64445163Ssklower 	int unit;
64545163Ssklower {
64645163Ssklower 	register struct dp_softc *dp;
64745163Ssklower 
64845228Ssklower 	/* currently not armed */
64945228Ssklower 	dpstat.timeout++;
65045163Ssklower 	dp = &dp_softc[unit];
65145228Ssklower 	if (dp->dp_if.if_flags & IFF_OACTIVE) {
65245228Ssklower 		dpstart(&dp->dp_if);
65345163Ssklower 	}
65445163Ssklower }
65545228Ssklower /*
65645228Ssklower  * For debugging loopback activity.
65745228Ssklower  */
65845228Ssklower static char pppheader[4] = { -1, 3, 0, 0x21 };
65945228Ssklower int dp_louts;
66045228Ssklower 
66145228Ssklower dptestoutput(ifp, m, dst, rt)
66245228Ssklower register struct ifnet *ifp;
66345228Ssklower register struct mbuf *m;
66445228Ssklower struct sockaddr *dst;
66545228Ssklower struct rtentry *rt;
66645228Ssklower {
66745228Ssklower 	/*
66845228Ssklower 	 * Queue message on interface, and start output if interface
66945228Ssklower 	 * not yet active.
67045228Ssklower 	 */
67145228Ssklower 	int s = splimp(), error = 0;
67245228Ssklower 	dp_louts++;
67345228Ssklower 	M_PREPEND(m, sizeof pppheader, M_DONTWAIT);
67445228Ssklower 	if (m == 0) {
67545228Ssklower 		splx(s);
67645228Ssklower 		return ENOBUFS;
67745228Ssklower 	}
67845228Ssklower 	bcopy(pppheader, mtod(m, caddr_t), sizeof pppheader);
67945228Ssklower 	if (IF_QFULL(&ifp->if_snd)) {
68045228Ssklower 		IF_DROP(&ifp->if_snd);
68145228Ssklower 	    /* printf("%s%d: HDLC says OK to send but queue full, may hang\n",
68245228Ssklower 			ifp->if_name, ifp->if_unit);*/
68345228Ssklower 		m_freem(m);
68445228Ssklower 		error = ENOBUFS;
68545228Ssklower 	} else {
68645228Ssklower 		IF_ENQUEUE(&ifp->if_snd, m);
68745228Ssklower 		if ((ifp->if_flags & IFF_OACTIVE) == 0)
68845228Ssklower 			(*ifp->if_start)(ifp);
68945228Ssklower 	}
69045228Ssklower 	splx(s);
69145228Ssklower 	return (error);
69245228Ssklower }
69345228Ssklower 
69445163Ssklower #endif
695