xref: /csrg-svn/sys/netiso/if_un.eg (revision 45432)
1*45432Sbostic/*
2*45432Sbostic * Copyright IBM Corporation 1987,1990
3*45432Sbostic *
4*45432Sbostic * All Rights Reserved
5*45432Sbostic *
6*45432Sbostic * Permission to use, copy, modify, and distribute this software and its
7*45432Sbostic * documentation for any purpose and without fee is hereby granted,
8*45432Sbostic * provided that the above copyright notice appear in all copies and that
9*45432Sbostic * both that copyright notice and this permission notice appear in
10*45432Sbostic * supporting documentation, and that the name of IBM not be
11*45432Sbostic * used in advertising or publicity pertaining to distribution of the
12*45432Sbostic * software without specific, written prior permission.
13*45432Sbostic *
14*45432Sbostic * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*45432Sbostic * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR USE.
16*45432Sbostic * IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17*45432Sbostic * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18*45432Sbostic * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19*45432Sbostic * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
20*45432Sbostic * THIS SOFTWARE.
21*45432Sbostic *
22*45432Sbostic *	@(#)if_un.eg	7.1 (Berkeley) 10/29/90
23*45432Sbostic */
24*45432Sbostic
25*45432Sbostic/*
26*45432Sbostic * Ungermann-Bass PC-NIC (Ethernet) Adapter  (4.3 driver)
27*45432Sbostic */
28*45432Sbostic
29*45432Sbostic#include "un.h"
30*45432Sbostic#if NUN > 0
31*45432Sbostic
32*45432Sbostic#include "../machine/pte.h"
33*45432Sbostic
34*45432Sbostic#include "param.h"
35*45432Sbostic#include "systm.h"
36*45432Sbostic#include "mbuf.h"
37*45432Sbostic#include "buf.h"
38*45432Sbostic#include "protosw.h"
39*45432Sbostic#include "socket.h"
40*45432Sbostic#include "vmmac.h"
41*45432Sbostic#include "ioctl.h"
42*45432Sbostic#include "errno.h"
43*45432Sbostic
44*45432Sbostic#include "../net/if.h"
45*45432Sbostic#include "../net/netisr.h"
46*45432Sbostic#include "../net/route.h"
47*45432Sbostic
48*45432Sbostic#ifdef INET
49*45432Sbostic#include "../netinet/in.h"
50*45432Sbostic#include "../netinet/in_systm.h"
51*45432Sbostic#include "../netinet/in_var.h"
52*45432Sbostic#include "../netinet/ip.h"
53*45432Sbostic#include "../netinet/if_ether.h"
54*45432Sbostic#endif INET
55*45432Sbostic
56*45432Sbostic#ifdef NS
57*45432Sbostic#include "../netns/ns.h"
58*45432Sbostic#include "../netns/ns_if.h"
59*45432Sbostic#endif NS
60*45432Sbostic
61*45432Sbostic#ifdef	ISO
62*45432Sbostic#include "../netargo/if_clnp.h"
63*45432Sbostic#include "../netargo/iso.h"
64*45432Sbostic#include "../netargo/iso_var.h"
65*45432Sbostic#include "../netargo/argo_debug.h"
66*45432Sbostic#endif	ISO
67*45432Sbostic
68*45432Sbostic#include "../machine/io.h"
69*45432Sbostic#include "if_unreg.h"
70*45432Sbostic#ifdef	IEEELLC
71*45432Sbostic#include "if_llc.h"
72*45432Sbostic#endif	IEEELLC
73*45432Sbostic#include "../machineio/ioccvar.h"
74*45432Sbostic#include "../machine/debug.h"
75*45432Sbostic
76*45432Sbosticint	unprobe(), unattach();
77*45432Sbostic
78*45432Sbostic#ifdef AT
79*45432Sbosticcaddr_t unstd[] = { (caddr_t) 0xa0000, (caddr_t) 0xa8000,
80*45432Sbostic	(caddr_t) 0xb0000, (caddr_t) 0xb8000, 0 };
81*45432Sbostic#else
82*45432Sbosticcaddr_t unstd[] = { (caddr_t) 0xf4080000, (caddr_t) 0xf4088000,
83*45432Sbostic	(caddr_t) 0xf4090000, (caddr_t) 0xf4098000, 0 };
84*45432Sbostic#endif AT
85*45432Sbostic
86*45432Sbosticstruct	iocc_device *uninfo[NUN];
87*45432Sbostic
88*45432Sbosticint	unint(),  uninit(), unioctl(), unoutput(), unreset();
89*45432Sbostic
90*45432Sbosticstruct	iocc_driver undriver =
91*45432Sbostic	{ unprobe, 0, unattach, 0, unstd, "un", uninfo,
92*45432Sbostic		0, 0, unint, UN_EADDROFF };
93*45432Sbostic
94*45432Sbosticstruct	mbuf *unget();
95*45432Sbostic
96*45432Sbostic/*
97*45432Sbostic * Ethernet software status per adapter.
98*45432Sbostic */
99*45432Sbosticstruct	un_softc {
100*45432Sbostic	struct	arpcom us_ac;		/* generic network interface stuff */
101*45432Sbostic#define	us_if	us_ac.ac_if		/* ifnet struct */
102*45432Sbostic#define	us_addr	us_ac.ac_enaddr		/* hardware (i.e. ethernet) address */
103*45432Sbostic	short	us_oactive;		/* 1 => output active */
104*45432Sbostic	short	us_nextpage;		/* next receive buffer page */
105*45432Sbostic	short	us_xbuf;		/* in-use xmt buf (if output active) */
106*45432Sbostic	short	us_xfull[2];		/* 1 => a full xmt buf */
107*45432Sbostic	short	us_xstart[2];		/* start address used in unstart */
108*45432Sbostic} un_softc[NUN];
109*45432Sbostic
110*45432Sbostic#ifdef DEBUG
111*45432Sbosticchar undebug = 0;
112*45432Sbostic#endif DEBUG
113*45432Sbostic
114*45432Sbostic#ifdef ATR
115*45432Sbostic#define move_window(window, addr)	{\
116*45432Sbostic	int real_addr;\
117*45432Sbostic	int new_window;\
118*45432Sbostic	\
119*45432Sbostic	window = get_128_window();\
120*45432Sbostic	real_addr = 0xfffff & (int) addr;\
121*45432Sbostic	new_window = real_addr & 0xe0000;\
122*45432Sbostic	set_128_window(new_window);\
123*45432Sbostic	addr = (struct undevice *) (real_addr - new_window);\
124*45432Sbostic}
125*45432Sbostic
126*45432Sbostic#define restore_window(window)	set_128_window(window)
127*45432Sbostic#define bcopyin(from,to,len) bcopy((from)+pcif_128_fw,to,len)
128*45432Sbostic#define bcopyout(from,to,len) bcopy(from,(to)+pcif_128_fw,len)
129*45432Sbostic#endif ATR
130*45432Sbostic
131*45432Sbostic#ifdef IBMRTPC
132*45432Sbostic#define bcopyin bcopy
133*45432Sbostic#define bcopyout bcopy
134*45432Sbostic#endif IBMRTPC
135*45432Sbostic/*
136*45432Sbostic *  unprobe - try to generate an interrupt (to see if the board is there)
137*45432Sbostic */
138*45432Sbosticunprobe(p)
139*45432Sbostic	register caddr_t p;
140*45432Sbostic{
141*45432Sbostic	register struct undevice *addr = (struct undevice *) p;
142*45432Sbostic#ifdef ATR
143*45432Sbostic	register int old_window;
144*45432Sbostic	move_window(old_window, addr);
145*45432Sbostic#endif ATR
146*45432Sbostic	(void) unzap(addr);
147*45432Sbostic	UN_GLOBIENB(0);			/* global interrrupt enable */
148*45432Sbostic	MM_OUT(&addr->un_csr, UN_GSFTINT);  /* generate software interrupt */
149*45432Sbostic	PROBE_DELAY(100000);
150*45432Sbostic	MM_OUT(&addr->un_csr, 0);
151*45432Sbostic#ifdef ATR
152*45432Sbostic	restore_window(old_window);
153*45432Sbostic#endif ATR
154*45432Sbostic	return(PROBE_OK);
155*45432Sbostic}
156*45432Sbostic
157*45432Sbostic/*
158*45432Sbostic *  unattach - make the interface available to the network software
159*45432Sbostic *  (if the auto-configuration software determines that the interface
160*45432Sbostic *  exists).  The system will initialize the interface when it is
161*45432Sbostic *  ready to accept packets.
162*45432Sbostic */
163*45432Sbosticunattach(iod)
164*45432Sbostic	register struct iocc_device *iod;
165*45432Sbostic{
166*45432Sbostic	register struct un_softc *us = &un_softc[iod->iod_unit];
167*45432Sbostic	register struct ifnet *ifp = &us->us_if;
168*45432Sbostic	register struct undevice *addr = (struct undevice *) iod->iod_addr;
169*45432Sbostic	register int i;
170*45432Sbostic#ifdef ATR
171*45432Sbostic	register int old_window;
172*45432Sbostic
173*45432Sbostic	move_window(old_window, addr);
174*45432Sbostic#endif ATR
175*45432Sbostic	ifp->if_unit = iod->iod_unit;
176*45432Sbostic	ifp->if_name = "un";
177*45432Sbostic
178*45432Sbostic#ifdef	IEEELLC
179*45432Sbostic	ifp->if_mtu = ETHERMTU - 3;		/* 3 bytes for UI LLC frame */
180*45432Sbostic#else
181*45432Sbostic	ifp->if_mtu = ETHERMTU;
182*45432Sbostic#endif	IEEELCC
183*45432Sbostic
184*45432Sbostic	/*
185*45432Sbostic	 * Read the ethernet address off the board.
186*45432Sbostic	 * Save it and also write it to the edlc chip.
187*45432Sbostic	 */
188*45432Sbostic	for (i = 0; i < ETH_ADDR_SIZE; i++){
189*45432Sbostic		us->us_addr[i] = MM_IN(&addr->un_eprom[UN_EADDROFF+i]);
190*45432Sbostic		MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]);
191*45432Sbostic	}
192*45432Sbostic	printf("un%d: ethernet address ", ifp->if_unit);
193*45432Sbostic	unprintethaddr(us->us_addr);
194*45432Sbostic	printf("\n");
195*45432Sbostic	ifp->if_init = uninit;
196*45432Sbostic	ifp->if_ioctl = unioctl;
197*45432Sbostic	ifp->if_output = unoutput;
198*45432Sbostic	ifp->if_reset = unreset;
199*45432Sbostic	ifp->if_flags = IFF_BROADCAST;
200*45432Sbostic#ifdef	ISO
201*45432Sbostic	ifp->if_flags |= IFF_EAVESDROP;
202*45432Sbostic#endif	ISO
203*45432Sbostic	if_attach(ifp);
204*45432Sbostic	DEBUGF(undebug, printf("un%d: attached\n", iod->iod_unit);)
205*45432Sbostic#ifdef ATR
206*45432Sbostic	restore_window(old_window);
207*45432Sbostic#endif ATR
208*45432Sbostic}
209*45432Sbostic
210*45432Sbostic/*
211*45432Sbostic *  unreset - reset interface
212*45432Sbostic */
213*45432Sbosticunreset(unit)
214*45432Sbostic	register unsigned int unit;
215*45432Sbostic{
216*45432Sbostic	register struct iocc_device *iod;
217*45432Sbostic
218*45432Sbostic	if (unit < NUN && (iod = uninfo[unit]) != 0 && iod->iod_alive != 0){
219*45432Sbostic		un_softc[unit].us_if.if_flags &= ~IFF_RUNNING;
220*45432Sbostic		DEBUGF(undebug, printf("un%d: reset\n", unit);)
221*45432Sbostic		uninit(unit);
222*45432Sbostic	}
223*45432Sbostic}
224*45432Sbostic
225*45432Sbostic/*
226*45432Sbostic *  uninit - initialize interface, enable packet reception, start any
227*45432Sbostic *  pending writes
228*45432Sbostic */
229*45432Sbosticuninit(unit)
230*45432Sbostic	register int unit;
231*45432Sbostic{
232*45432Sbostic	register struct un_softc *us = &un_softc[unit];
233*45432Sbostic	register struct ifnet *ifp = &us->us_if;
234*45432Sbostic	register int s;
235*45432Sbostic	register struct undevice *addr;
236*45432Sbostic	register int i;
237*45432Sbostic
238*45432Sbostic	if (ifp->if_addrlist == (struct ifaddr *) 0){
239*45432Sbostic		/* no address */
240*45432Sbostic		return;
241*45432Sbostic	}
242*45432Sbostic	if ((ifp->if_flags & IFF_RUNNING) == 0){
243*45432Sbostic		int old_window;
244*45432Sbostic
245*45432Sbostic		addr = (struct undevice *) (uninfo[unit]->iod_addr);
246*45432Sbostic#ifdef ATR
247*45432Sbostic		move_window(old_window, addr);
248*45432Sbostic#endif ATR
249*45432Sbostic		s = splimp();
250*45432Sbostic		us->us_nextpage = unzap(addr);	/* initialize hardware */
251*45432Sbostic			/* unzap returns next receive page to be used */
252*45432Sbostic		for (i = 0; i < ETH_ADDR_SIZE; i++){
253*45432Sbostic			MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]);
254*45432Sbostic		}
255*45432Sbostic		us->us_oactive = 0;	/* output not active */
256*45432Sbostic		/*  turn adapter on */
257*45432Sbostic		ifp->if_flags |= IFF_RUNNING;
258*45432Sbostic		MM_OUT(&addr->un_csr, UN_PAVIENB);
259*45432Sbostic			/* Allow packet available interrupts */
260*45432Sbostic		UN_GLOBIENB(us->us_nextpage);	/* global interrrupt enable */
261*45432Sbostic		if (ifp->if_snd.ifq_head){	/* anything on send queue */
262*45432Sbostic			struct mbuf *m;
263*45432Sbostic
264*45432Sbostic			IF_DEQUEUE(&ifp->if_snd, m);
265*45432Sbostic			unput(us, addr, m, 0);
266*45432Sbostic			unstart(us, addr, 0);
267*45432Sbostic			if (ifp->if_snd.ifq_head){
268*45432Sbostic				IF_DEQUEUE(&ifp->if_snd, m);
269*45432Sbostic				unput(us, addr, m, 1);
270*45432Sbostic			}
271*45432Sbostic		}
272*45432Sbostic		splx(s);
273*45432Sbostic#ifdef ATR
274*45432Sbostic		restore_window(old_window);
275*45432Sbostic#endif ATR
276*45432Sbostic	}
277*45432Sbostic	DEBUGF(undebug, printf("un%d: init'ed\n", unit);)
278*45432Sbostic}
279*45432Sbostic
280*45432Sbostic/*
281*45432Sbostic *  unstart - start output from one of the adapter's 2 transmit buffers
282*45432Sbostic */
283*45432Sbosticunstart(us, addr, xbuf)
284*45432Sbostic	register struct un_softc *us;
285*45432Sbostic	register struct undevice *addr;
286*45432Sbostic	register int xbuf;
287*45432Sbostic{
288*45432Sbostic	us->us_oactive = 1;
289*45432Sbostic	us->us_xbuf = xbuf;
290*45432Sbostic	UN_XMIT(addr, us->us_xstart[xbuf]);
291*45432Sbostic	MM_OUT(&addr->un_csr, UN_IENABLE); /* enable transmit done interrupt */
292*45432Sbostic}
293*45432Sbostic
294*45432Sbostic/*
295*45432Sbostic *  unint - interrupt handler.  find the cause of the interrupt and
296*45432Sbostic *  dispatch an appropriate handler routine.
297*45432Sbostic */
298*45432Sbosticunint(unit)
299*45432Sbostic	register int unit;
300*45432Sbostic{
301*45432Sbostic	register struct un_softc *us = &un_softc[unit];
302*45432Sbostic	register struct undevice *addr =
303*45432Sbostic	  (struct undevice *) uninfo[unit]->iod_addr;
304*45432Sbostic	register char status;
305*45432Sbostic	register int rc = 1;
306*45432Sbostic#ifdef ATR
307*45432Sbostic	register int old_window;
308*45432Sbostic
309*45432Sbostic	move_window(old_window, addr);
310*45432Sbostic#endif ATR
311*45432Sbostic
312*45432Sbostic	UN_DISABLE(us->us_nextpage);
313*45432Sbostic	while ((status = ~MM_IN(&addr->un_csr)) & UN_PAVINT){
314*45432Sbostic		DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b",
315*45432Sbostic		  unit, status & 0xff, UN_CSRBITS);)
316*45432Sbostic		unrint(unit, us, addr);
317*45432Sbostic		rc = 0;
318*45432Sbostic	}
319*45432Sbostic	if (status & UN_TXRINT){
320*45432Sbostic		DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b",
321*45432Sbostic		  unit, status & 0xff, UN_CSRBITS);)
322*45432Sbostic		unxint(unit, us, addr);
323*45432Sbostic		rc = 0;
324*45432Sbostic	}
325*45432Sbostic	UN_ENABLE(us->us_nextpage);
326*45432Sbostic#ifdef ATR
327*45432Sbostic	restore_window(old_window);
328*45432Sbostic#endif ATR
329*45432Sbostic	return(rc);
330*45432Sbostic}
331*45432Sbostic
332*45432Sbostic/*
333*45432Sbostic *  unrint - interrupt handler for packet reception.
334*45432Sbostic *
335*45432Sbostic *  log error if error bits are latched,  examine packet to determine
336*45432Sbostic *  type, if can't determine packet length from type, drop packet.
337*45432Sbostic *  otherwise decapsulate packet based on type and pass to an appropriate
338*45432Sbostic *  higher-level input routine.
339*45432Sbostic */
340*45432Sbosticunrint(unit, us, addr)
341*45432Sbostic	int unit;
342*45432Sbostic	register struct un_softc *us;
343*45432Sbostic	register struct undevice *addr;
344*45432Sbostic{
345*45432Sbostic	register struct ether_header *eh;
346*45432Sbostic    	register struct mbuf *m;
347*45432Sbostic	register int len;
348*45432Sbostic	register int off;
349*45432Sbostic	int resid;
350*45432Sbostic	struct ifqueue *inq;
351*45432Sbostic	char status = MM_IN(&addr->un_edlc.rstat);
352*45432Sbostic	u_short	type;
353*45432Sbostic	u_short ungetushortatoff();
354*45432Sbostic#ifdef	IEEELLC
355*45432Sbostic	struct ether_header	ehbuf;
356*45432Sbostic#endif	IEEELLC
357*45432Sbostic
358*45432Sbostic	MM_OUT(&addr->un_edlc.rstat, status);	/* clear status */
359*45432Sbostic	/* (the hardware xor's in the value of status setting rstat to 0) */
360*45432Sbostic	DEBUGF(undebug & 0x2, printf(" rstat = %b", status, RS_BITS);)
361*45432Sbostic	/*
362*45432Sbostic	 *  Latch errors.  (Errors found correspond to packets
363*45432Sbostic	 *  that were received prior to the current packet
364*45432Sbostic	 *  since packet available interrupts are generated
365*45432Sbostic	 *  for good packets only.)
366*45432Sbostic	 */
367*45432Sbostic	if (status & RS_ERR){
368*45432Sbostic		DEBUGF(undebug, printf("unrint: input error\n");)
369*45432Sbostic		us->us_if.if_ierrors++;
370*45432Sbostic	}
371*45432Sbostic	us->us_if.if_ipackets++;
372*45432Sbostic
373*45432Sbostic	/*
374*45432Sbostic	 *  determine the length of the received packet.
375*45432Sbostic	 */
376*45432Sbostic	len = 0;
377*45432Sbostic	off = us->us_nextpage;
378*45432Sbostic
379*45432Sbostic#define BUMP(page)	if (++(page) == UN_NUMRBUFS) page = 0
380*45432Sbostic	while ((MM_IN(&addr->un_pram[us->us_nextpage]) & UN_LAST_PAGE) == 0){
381*45432Sbostic		len += UN_RBUFSIZE;
382*45432Sbostic		BUMP(us->us_nextpage);
383*45432Sbostic	}
384*45432Sbostic	len += (MM_IN(&addr->un_pram[us->us_nextpage]) &
385*45432Sbostic		UN_PAGE_LENGTH_MASK) + 1;
386*45432Sbostic	BUMP(us->us_nextpage);
387*45432Sbostic#undef BUMP
388*45432Sbostic	DEBUGF(undebug & 0x2, printf(" len = %d ", len);)
389*45432Sbostic	if (len > UN_XBSIZE){
390*45432Sbostic		printf("un%d: huge packet!\n",unit);
391*45432Sbostic		goto chuckit;
392*45432Sbostic	}
393*45432Sbostic	/*
394*45432Sbostic	 * Process the packet
395*45432Sbostic	 */
396*45432Sbostic	eh = (struct ether_header *) &addr->un_rcvbuf[off][0];
397*45432Sbostic	DEBUGF(undebug & 0x2,
398*45432Sbostic		{  char cbuf[6];
399*45432Sbostic		printf(" from = ");
400*45432Sbostic		bcopyin(eh->ether_shost, cbuf, sizeof(cbuf));
401*45432Sbostic		unprintethaddr(cbuf);
402*45432Sbostic		printf("  to = ");
403*45432Sbostic		bcopyin(eh->ether_dhost, cbuf, sizeof(cbuf));
404*45432Sbostic		unprintethaddr(cbuf);
405*45432Sbostic		printf(" "); }
406*45432Sbostic	)
407*45432Sbostic	len -= sizeof(struct ether_header);
408*45432Sbostic	type = ntohs((u_short) MM_INW(&eh->ether_type));
409*45432Sbostic	/*
410*45432Sbostic	 *  The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL
411*45432Sbostic	 *  have (type - ETHERTYPE_TRAIL) * 512 bytes of data followed by
412*45432Sbostic	 *  a type field and then a (variable length) header
413*45432Sbostic	 */
414*45432Sbostic	if (type >= ETHERTYPE_TRAIL &&
415*45432Sbostic	    type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER){
416*45432Sbostic		off = (type - ETHERTYPE_TRAIL) * 512;
417*45432Sbostic		if (off >= ETHERMTU){
418*45432Sbostic			goto chuckit;
419*45432Sbostic		}
420*45432Sbostic		type = ungetushortatoff(addr, eh, off);
421*45432Sbostic		resid = ungetushortatoff(addr, eh, off + 2);
422*45432Sbostic		if (off + resid > len){
423*45432Sbostic			goto chuckit;
424*45432Sbostic		}
425*45432Sbostic		len = off + resid;
426*45432Sbostic	} else {
427*45432Sbostic		off = 0;
428*45432Sbostic	}
429*45432Sbostic	if (len == 0){
430*45432Sbostic		goto chuckit;
431*45432Sbostic	}
432*45432Sbostic
433*45432Sbostic#ifdef	IEEELLC
434*45432Sbostic	if (type <= ETHERMTU) {
435*45432Sbostic		/* may need ether_header for XID, TEST LLC functions */
436*45432Sbostic		ehbuf = *eh;
437*45432Sbostic	}
438*45432Sbostic#endif	IEEELLC
439*45432Sbostic
440*45432Sbostic	/*
441*45432Sbostic	 *  pull packet off interface.  if off is non-zero, the
442*45432Sbostic	 *  packet has a trailing "header".  unget will move this
443*45432Sbostic	 *  header to the front, but we still have to remove the
444*45432Sbostic	 *  type and length fields from the front of the data.
445*45432Sbostic	 */
446*45432Sbostic	m = unget(addr, (char *) eh, len, off, &us->us_if);
447*45432Sbostic	/*
448*45432Sbostic	 *  update the full page pointer and clear the packet available
449*45432Sbostic	 *  flag if necessary.  update the fpp here to free the on-board
450*45432Sbostic	 *  receive pages as soon as possible.
451*45432Sbostic	 */
452*45432Sbostic	unupdatefpp(addr, us->us_nextpage);
453*45432Sbostic	if (m != 0){
454*45432Sbostic		if (off){
455*45432Sbostic#ifdef	ISO
456*45432Sbostic			/*
457*45432Sbostic			 *	Move snpa header over by 4 bytes to skip
458*45432Sbostic			 *	the trailer Type and Header length fields.
459*45432Sbostic			 */
460*45432Sbostic			struct snpa_hdr		sh;
461*45432Sbostic
462*45432Sbostic			bcopy(mtod(m, char *), (caddr_t)&sh, sizeof(struct snpa_hdr));
463*45432Sbostic			m->m_off += 2 * sizeof(u_short);
464*45432Sbostic			m->m_len -= 2 * sizeof(u_short);
465*45432Sbostic			bcopy((caddr_t)&sh, mtod(m, char *), sizeof(struct snpa_hdr));
466*45432Sbostic#else	ISO
467*45432Sbostic			struct ifnet *ifp;
468*45432Sbostic			/*
469*45432Sbostic			 * bcopy is used since word moves must be on 4 byte
470*45432Sbostic			 * boundaries on the RT PC
471*45432Sbostic			 */
472*45432Sbostic			bcopy(mtod(m, char *), (char *) &ifp, sizeof(ifp));
473*45432Sbostic			m->m_off += 2 * sizeof(u_short);
474*45432Sbostic			m->m_len -= 2 * sizeof(u_short);
475*45432Sbostic			bcopy((char *) &ifp, mtod(m, char *), sizeof(ifp));
476*45432Sbostic#endif	ISO
477*45432Sbostic		}
478*45432Sbostic		switch (type){
479*45432Sbostic#ifdef INET
480*45432Sbostic		case ETHERTYPE_IP:
481*45432Sbostic		    {
482*45432Sbostic			int s;
483*45432Sbostic
484*45432Sbostic			DEBUGF(undebug & 0x2, printf("ip packet\n");)
485*45432Sbostic			schednetisr(NETISR_IP);
486*45432Sbostic			s = splimp();
487*45432Sbostic			inq = &ipintrq;
488*45432Sbostic			if (IF_QFULL(inq)){
489*45432Sbostic				DEBUGF(undebug & 0x2, printf(" qfull\n");)
490*45432Sbostic				IF_DROP(inq);
491*45432Sbostic				m_freem(m);
492*45432Sbostic			} else {
493*45432Sbostic				IF_ENQUEUE(inq, m);
494*45432Sbostic				DEBUGF(undebug & 0x2, printf(" queued\n");)
495*45432Sbostic			}
496*45432Sbostic			splx(s);
497*45432Sbostic			break;
498*45432Sbostic		    }
499*45432Sbostic
500*45432Sbostic		case ETHERTYPE_ARP:
501*45432Sbostic			DEBUGF(undebug & 0x2, printf("arp packet\n");)
502*45432Sbostic			arpinput(&us->us_ac, m);  /* arpinput frees m */
503*45432Sbostic			break;
504*45432Sbostic#endif INET
505*45432Sbostic#ifdef NS
506*45432Sbostic		case ETHERTYPE_NS:
507*45432Sbostic			DEBUGF(undebug & 0x2, printf("ns packet\n");)
508*45432Sbostic			schednetisr(NETISR_NS);
509*45432Sbostic			inq = &nsintrq;
510*45432Sbostic			break;
511*45432Sbostic#endif NS
512*45432Sbostic#ifndef	IEEELLC
513*45432Sbostic#ifdef	ISO
514*45432Sbostic		case ETHERTYPE_CLNP:	/* should be CLNL */
515*45432Sbostic			DEBUGF(undebug & 0x2, printf("clnl packet\n");)
516*45432Sbostic
517*45432Sbostic			/* IFF_EAVESDROP can not be turned off for Ethernet */
518*45432Sbostic
519*45432Sbostic			schednetisr(NETISR_CLNP);
520*45432Sbostic			inq = &clnlintrq;
521*45432Sbostic			if (IF_QFULL(inq)){
522*45432Sbostic				DEBUGF(undebug & 0x2, printf(" qfull\n");)
523*45432Sbostic				IF_DROP(inq);
524*45432Sbostic				m_freem(m);
525*45432Sbostic			} else {
526*45432Sbostic				IF_ENQUEUE(inq, m);
527*45432Sbostic				DEBUGF(undebug & 0x2, printf(" queued\n");)
528*45432Sbostic			}
529*45432Sbostic			break;
530*45432Sbostic#endif	ISO
531*45432Sbostic		default:
532*45432Sbostic			DEBUGF(undebug & 0x2, printf("unknown packet\n");)
533*45432Sbostic			m_freem(m);
534*45432Sbostic			break;
535*45432Sbostic#else
536*45432Sbostic		default: {
537*45432Sbostic			struct llc *l;
538*45432Sbostic			caddr_t		pkt_start;
539*45432Sbostic#ifdef	ISO
540*45432Sbostic#define	PREPENDED_SIZE	sizeof(struct snpa_hdr)
541*45432Sbostic#else
542*45432Sbostic#define	PREPENDED_SIZE	sizeof(struct ifnet *)
543*45432Sbostic#endif	ISO
544*45432Sbostic			if (type > ETHERMTU)
545*45432Sbostic				goto not802;
546*45432Sbostic
547*45432Sbostic			/*
548*45432Sbostic			 *	This assumes that the snpa header is in the same mbuf
549*45432Sbostic			 *	as the llc header. Currently this is ok, but if
550*45432Sbostic			 *	unget allocates a cluster, this will not be the case
551*45432Sbostic			 */
552*45432Sbostic			pkt_start = mtod(m, caddr_t);
553*45432Sbostic			l = (struct llc *) (pkt_start + PREPENDED_SIZE);
554*45432Sbostic
555*45432Sbostic			IFDEBUG(D_ETHER)
556*45432Sbostic				printf("unrint: llc: length %d, control x%x:\n", type,
557*45432Sbostic					l->llc_control);
558*45432Sbostic			ENDDEBUG
559*45432Sbostic
560*45432Sbostic			switch (l->llc_control) {
561*45432Sbostic			case LLC_UI:
562*45432Sbostic			/* LLC_UI_P forbidden in class 1 service */
563*45432Sbostic#ifdef	ISO
564*45432Sbostic				if (l->llc_dsap == LLC_ISO_LSAP) {
565*45432Sbostic					if ((IS_MULTICAST(ehbuf.ether_dhost)) &&
566*45432Sbostic						((us->us_if.if_flags & IFF_EAVESDROP) == 0) &&
567*45432Sbostic						(!snpac_ownmulti(ehbuf.ether_dhost, 6))) {
568*45432Sbostic						m_freem(m);
569*45432Sbostic						return;
570*45432Sbostic					}
571*45432Sbostic
572*45432Sbostic					/* move struct snpa_header over the llc header */
573*45432Sbostic					clnp_ypocb(pkt_start, pkt_start + 3,
574*45432Sbostic						PREPENDED_SIZE);
575*45432Sbostic					m->m_off += 3;
576*45432Sbostic					m->m_len -= 3;
577*45432Sbostic
578*45432Sbostic					DEBUGF(undebug & 0x2, printf("clnp packet\n");)
579*45432Sbostic					schednetisr(NETISR_CLNP);
580*45432Sbostic					inq = &clnlintrq;
581*45432Sbostic					if (IF_QFULL(inq)){
582*45432Sbostic						DEBUGF(undebug & 0x2, printf(" qfull\n");)
583*45432Sbostic						IF_DROP(inq);
584*45432Sbostic						m_freem(m);
585*45432Sbostic					} else {
586*45432Sbostic						IF_ENQUEUE(inq, m);
587*45432Sbostic						DEBUGF(undebug & 0x2, printf(" queued\n");)
588*45432Sbostic					}
589*45432Sbostic					return;
590*45432Sbostic			    } else {
591*45432Sbostic					IFDEBUG(D_ETHER)
592*45432Sbostic						printf("unrint: unknown llc sap\n");
593*45432Sbostic					ENDDEBUG
594*45432Sbostic					m_freem(m);
595*45432Sbostic					return;
596*45432Sbostic				}
597*45432Sbostic#endif	ISO
598*45432Sbostic			    break;
599*45432Sbostic/* LLC_XID, LLC_XID_P, LLC_TEST, and LLC_TEST_P are untested */
600*45432Sbostic			case LLC_XID:
601*45432Sbostic			case LLC_XID_P:	/* control field is untouched for resp */
602*45432Sbostic			    if(m->m_len < 6)
603*45432Sbostic					goto not802;
604*45432Sbostic			    l->llc_fid = LLC_IEEE_basic_format;
605*45432Sbostic			    l->llc_class = LLC_CLASS1;
606*45432Sbostic			    l->llc_window = 0;
607*45432Sbostic			    l->llc_dsap = l->llc_ssap = 0;
608*45432Sbostic			    /* FALL THROUGH */
609*45432Sbostic			case LLC_TEST:
610*45432Sbostic			case LLC_TEST_P: {
611*45432Sbostic				struct ifnet *ifp = &us->us_if;
612*45432Sbostic			    struct sockaddr_iso siso;
613*45432Sbostic			    u_char c = l->llc_dsap;
614*45432Sbostic			    l->llc_dsap = l->llc_ssap;
615*45432Sbostic			    l->llc_ssap = c;
616*45432Sbostic
617*45432Sbostic			    /* Do not TEST or XID to multicasts */
618*45432Sbostic			    if (IS_MULTICAST(ehbuf.ether_dhost)) {
619*45432Sbostic					m_freem(m);
620*45432Sbostic					break;
621*45432Sbostic				}
622*45432Sbostic
623*45432Sbostic			    siso.siso_family = AF_ISO;
624*45432Sbostic				bcopy(ehbuf.ether_shost, siso.siso_addr.sna_idi, 6);
625*45432Sbostic				siso.siso_addr.isoa_afi = AFI_SNA;
626*45432Sbostic				siso.siso_addr.isoa_len = 7;
627*45432Sbostic
628*45432Sbostic				/* trim off prepended snpa_hdr or ifp */
629*45432Sbostic				m->m_off += PREPENDED_SIZE;
630*45432Sbostic				m->m_len -= PREPENDED_SIZE;
631*45432Sbostic
632*45432Sbostic			    unoutput(ifp, m, &siso);
633*45432Sbostic			    return;
634*45432Sbostic			}
635*45432Sbostic			not802:
636*45432Sbostic			default:
637*45432Sbostic				DEBUGF(undebug & 0x2, printf("unknown packet\n");)
638*45432Sbostic				m_freem(m);
639*45432Sbostic				break;
640*45432Sbostic			}
641*45432Sbostic		}
642*45432Sbostic#endif	IEEELLC
643*45432Sbostic		}
644*45432Sbostic	}
645*45432Sbostic	return;
646*45432Sbosticchuckit:
647*45432Sbostic	DEBUGF(undebug, printf("unrint: packet dropped\n");)
648*45432Sbostic	unupdatefpp(addr, us->us_nextpage);
649*45432Sbostic}
650*45432Sbostic
651*45432Sbostic/*
652*45432Sbostic *  unxint -  interrupt handler for transmit ready
653*45432Sbostic */
654*45432Sbosticunxint(unit, us, addr)
655*45432Sbostic	register int unit;
656*45432Sbostic	register struct un_softc *us;
657*45432Sbostic	register struct undevice *addr;
658*45432Sbostic{
659*45432Sbostic	register char status;
660*45432Sbostic	register int next_buf;
661*45432Sbostic
662*45432Sbostic	/*
663*45432Sbostic	 *  collect stats on last packet
664*45432Sbostic	 */
665*45432Sbostic	status = MM_IN(&addr->un_edlc.xstat);
666*45432Sbostic	MM_OUT(&addr->un_edlc.xstat, status);	/* clear status bits */
667*45432Sbostic	DEBUGF(undebug & 0x2, printf(" unxint: xstat = %b\n",
668*45432Sbostic	  status & 0xff, XS_BITS);)
669*45432Sbostic	if (status & XS_16CL){
670*45432Sbostic		us->us_if.if_collisions += 16;
671*45432Sbostic		us->us_if.if_oerrors++;
672*45432Sbostic		printf("un%d: ethernet jammed\n", unit);
673*45432Sbostic	}
674*45432Sbostic	else if (status & XS_SHRT){
675*45432Sbostic		us->us_if.if_oerrors++;
676*45432Sbostic		printf( "un%d: ethernet not responding (is it connected?)\n",
677*45432Sbostic			unit);
678*45432Sbostic	}
679*45432Sbostic	else {
680*45432Sbostic		us->us_if.if_opackets++;
681*45432Sbostic		us->us_if.if_collisions += UN_NCOLL(addr);
682*45432Sbostic	}
683*45432Sbostic	DEBUGF(undebug & 0x2,
684*45432Sbostic	  printf(" ipkt = %d ierr = %d okt = %d oerr = %d coll = %d\n",
685*45432Sbostic	    us->us_if.if_ipackets, us->us_if.if_ierrors,
686*45432Sbostic	    us->us_if.if_opackets, us->us_if.if_oerrors,
687*45432Sbostic	    us->us_if.if_collisions);)
688*45432Sbostic	/*  mark the current transmit buffer empty */
689*45432Sbostic	us->us_xfull[us->us_xbuf] = 0;
690*45432Sbostic	/*  switch to the other transmit buffer */
691*45432Sbostic	next_buf = 1 - us->us_xbuf;
692*45432Sbostic	if (us->us_xfull[next_buf]){	/*  if it's full */
693*45432Sbostic		unstart(us, addr, next_buf);	/* start output from it */
694*45432Sbostic		if (us->us_if.if_snd.ifq_head){	/*  if more on out queue */
695*45432Sbostic			struct mbuf *m;
696*45432Sbostic
697*45432Sbostic			IF_DEQUEUE(&us->us_if.if_snd, m); /* fill empty buf */
698*45432Sbostic			unput(us, addr, m, 1 - next_buf);
699*45432Sbostic		}
700*45432Sbostic	}
701*45432Sbostic	else {	/*  the other transmit buffer is empty */
702*45432Sbostic		us->us_oactive = 0;
703*45432Sbostic		MM_OUT(&addr->un_csr, UN_PAVIENB);	/* Turn off TxRIENB */
704*45432Sbostic	}
705*45432Sbostic}
706*45432Sbostic
707*45432Sbostic/*
708*45432Sbostic *  unoutput - ethernet output routine.  encapsulate a packet of type
709*45432Sbostic *  family for the local net.  use trailer local net encapsulation if
710*45432Sbostic *  the number of bytes in the mbufs after the first is a multiple of
711*45432Sbostic *  512.
712*45432Sbostic */
713*45432Sbosticunoutput(ifp, m0, dst)
714*45432Sbostic	register struct ifnet *ifp;
715*45432Sbostic	register struct mbuf *m0;
716*45432Sbostic	register struct sockaddr *dst;
717*45432Sbostic{
718*45432Sbostic	u_short type;
719*45432Sbostic	int s;
720*45432Sbostic	int error;
721*45432Sbostic	char edst[ETH_ADDR_SIZE];
722*45432Sbostic	struct in_addr idst;
723*45432Sbostic	register struct un_softc *us = &un_softc[ifp->if_unit];
724*45432Sbostic	register struct mbuf *m = m0;
725*45432Sbostic	register struct ether_header *eh;
726*45432Sbostic	int off;
727*45432Sbostic	struct mbuf *m_get();
728*45432Sbostic	int usetrailers;
729*45432Sbostic
730*45432Sbostic	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)){
731*45432Sbostic		error = ENETDOWN;
732*45432Sbostic		goto bad;
733*45432Sbostic	}
734*45432Sbostic	switch (dst->sa_family){
735*45432Sbostic
736*45432Sbostic#ifdef INET
737*45432Sbostic	case AF_INET:
738*45432Sbostic		idst = ((struct sockaddr_in *)dst)->sin_addr;
739*45432Sbostic		if (!arpresolve(&us->us_ac, m, &idst, edst, &usetrailers)){
740*45432Sbostic			/* not resolved */
741*45432Sbostic			return(0);
742*45432Sbostic		}
743*45432Sbostic		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
744*45432Sbostic		if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
745*45432Sbostic		  m->m_off >= MMINOFF + 2 * sizeof(u_short)){
746*45432Sbostic			type = ETHERTYPE_TRAIL + (off>>9);
747*45432Sbostic			m->m_off -= 2 * sizeof(u_short);
748*45432Sbostic			m->m_len += 2 * sizeof(u_short);
749*45432Sbostic			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
750*45432Sbostic			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
751*45432Sbostic			/*
752*45432Sbostic			 *  Packet to be sent with trailer, move first packet
753*45432Sbostic			 *  (control information) to end of chain.
754*45432Sbostic			 */
755*45432Sbostic			while (m->m_next)
756*45432Sbostic				m = m->m_next;
757*45432Sbostic			m->m_next = m0;
758*45432Sbostic			m = m0->m_next;
759*45432Sbostic			m0->m_next = 0;
760*45432Sbostic			m0 = m;
761*45432Sbostic		}
762*45432Sbostic		else {
763*45432Sbostic			type = ETHERTYPE_IP;
764*45432Sbostic		}
765*45432Sbostic		break;
766*45432Sbostic#endif INET
767*45432Sbostic#ifdef NS
768*45432Sbostic	case AF_NS:
769*45432Sbostic		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
770*45432Sbostic		  (caddr_t)edst, sizeof(edst));
771*45432Sbostic		type = ETHERTYPE_NS;
772*45432Sbostic		off = 0;
773*45432Sbostic		break;
774*45432Sbostic#endif NS
775*45432Sbostic#ifdef	ISO
776*45432Sbostic	case AF_ISO: {
777*45432Sbostic		int	ret;
778*45432Sbostic		int len;
779*45432Sbostic		struct iso_addr *dst_nsap = &((struct sockaddr_iso *)dst)->siso_addr;
780*45432Sbostic
781*45432Sbostic 		if ((ret = iso_tryloopback(m, dst)) >= 0)
782*45432Sbostic 			return (ret);
783*45432Sbostic 		else if (ret = iso_snparesolve(&us->us_ac.ac_if, dst_nsap, edst, &len)){
784*45432Sbostic  			/* not resolved */
785*45432Sbostic 			IFDEBUG(D_ETHER)
786*45432Sbostic 				printf("unoutput: clnp packet dropped\n");
787*45432Sbostic 			ENDDEBUG
788*45432Sbostic			m_freem(m);
789*45432Sbostic 			return(ret);
790*45432Sbostic 		} else if (len != 6) {
791*45432Sbostic  			printf("unoutput: snpa len is not 6 (%d)\n", len);
792*45432Sbostic			m_freem(m);
793*45432Sbostic  			return(ENETUNREACH);
794*45432Sbostic  		}
795*45432Sbostic
796*45432Sbostic#ifndef	IEEELLC
797*45432Sbostic		type = ETHERTYPE_CLNP;
798*45432Sbostic#else
799*45432Sbostic		/* check for enough space for LLC header */
800*45432Sbostic		{
801*45432Sbostic			struct mbuf *llcm;
802*45432Sbostic			char		*cp;
803*45432Sbostic			if (m->m_off >= MMAXOFF || m->m_off < MMINOFF + 3) {
804*45432Sbostic				MGET(llcm, M_DONTWAIT, MT_DATA);
805*45432Sbostic				if (llcm == NULL) {
806*45432Sbostic					m_freem(m);
807*45432Sbostic					return(0);
808*45432Sbostic				}
809*45432Sbostic				llcm->m_off = MMAXOFF - 3;
810*45432Sbostic				llcm->m_len = 3;
811*45432Sbostic				llcm->m_next = m;
812*45432Sbostic				m = llcm;
813*45432Sbostic			} else {
814*45432Sbostic				m->m_off -= 3;
815*45432Sbostic				m->m_len += 3;
816*45432Sbostic			}
817*45432Sbostic			type = m_datalen(m);
818*45432Sbostic
819*45432Sbostic			cp = mtod(m, u_char *);
820*45432Sbostic			cp[0] = cp[1] = LLC_ISO_LSAP; cp[2] = LLC_UI;
821*45432Sbostic			off = 0;
822*45432Sbostic		}
823*45432Sbostic#endif	IEEELLC
824*45432Sbostic		off = 0;
825*45432Sbostic		IFDEBUG(D_ETHER)
826*45432Sbostic			int i;
827*45432Sbostic			printf("unoutput: sending pkt to: ");
828*45432Sbostic			for (i=0; i<6; i++)
829*45432Sbostic				printf("%x ", edst[i] & 0xff);
830*45432Sbostic#ifdef	IEEELLC
831*45432Sbostic			printf(" llc len %d", type);
832*45432Sbostic#endif	IEEELLC
833*45432Sbostic			printf("\n");
834*45432Sbostic		ENDDEBUG
835*45432Sbostic		} break;
836*45432Sbostic#endif	ISO
837*45432Sbostic	case AF_UNSPEC:
838*45432Sbostic		eh = (struct ether_header *)dst->sa_data;
839*45432Sbostic		bcopy((char *)eh->ether_dhost, (caddr_t)edst, sizeof(edst));
840*45432Sbostic		type = eh->ether_type;
841*45432Sbostic		break;
842*45432Sbostic	default:
843*45432Sbostic		printf("un%d: can't handle af%d\n", ifp->if_unit,
844*45432Sbostic		  dst->sa_family);
845*45432Sbostic		error = EAFNOSUPPORT;
846*45432Sbostic		goto bad;
847*45432Sbostic	}
848*45432Sbostic	/*
849*45432Sbostic	 * Add local net header.  If no space in first mbuf,
850*45432Sbostic	 * allocate another.
851*45432Sbostic	 */
852*45432Sbostic	if (m->m_off > MMAXOFF ||
853*45432Sbostic	    MMINOFF + sizeof(struct ether_header) > m->m_off){
854*45432Sbostic		m = m_get(M_DONTWAIT, MT_HEADER);
855*45432Sbostic		/*
856*45432Sbostic		 *  Note:  m_get, m_freem etc. guard against concurrent
857*45432Sbostic		 *  updates to the list of free mbufs.
858*45432Sbostic		 */
859*45432Sbostic		if (m == 0){
860*45432Sbostic			error = ENOBUFS;
861*45432Sbostic			goto bad;
862*45432Sbostic		}
863*45432Sbostic		m->m_next = m0;
864*45432Sbostic		m->m_off = MMINOFF;
865*45432Sbostic		m->m_len = sizeof(struct ether_header);
866*45432Sbostic	} else {
867*45432Sbostic		m->m_off -= sizeof(struct ether_header);
868*45432Sbostic		m->m_len += sizeof(struct ether_header);
869*45432Sbostic	}
870*45432Sbostic	eh = mtod(m, struct ether_header *);
871*45432Sbostic	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof(edst));
872*45432Sbostic	bcopy((caddr_t)us->us_addr, (caddr_t)eh->ether_shost,
873*45432Sbostic	  sizeof(eh->ether_shost));
874*45432Sbostic	bcopy((caddr_t)&type, (caddr_t)&eh->ether_type, sizeof(u_short));
875*45432Sbostic
876*45432Sbostic	/*
877*45432Sbostic	 *  queue packet for transmission.  if there is an empty
878*45432Sbostic	 *  transmit buffer on the adapter, use it.
879*45432Sbostic	 */
880*45432Sbostic	s = splimp();
881*45432Sbostic	if (IF_QFULL(&ifp->if_snd)){
882*45432Sbostic		IF_DROP(&ifp->if_snd);
883*45432Sbostic		error = ENOBUFS;
884*45432Sbostic		goto qfull;
885*45432Sbostic	}
886*45432Sbostic	if (us->us_xfull[0] == 0 || us->us_xfull[1] == 0){ /* empty xmt buf */
887*45432Sbostic		struct undevice *addr = (struct undevice *)
888*45432Sbostic		  uninfo[ifp->if_unit]->iod_addr;
889*45432Sbostic		int next_buf;
890*45432Sbostic#ifdef ATR
891*45432Sbostic		int old_window;
892*45432Sbostic		move_window(old_window, addr);
893*45432Sbostic#endif ATR
894*45432Sbostic		if (us->us_xfull[0] == 0){
895*45432Sbostic			next_buf = 0;
896*45432Sbostic		}
897*45432Sbostic		else {
898*45432Sbostic			next_buf = 1;
899*45432Sbostic		}
900*45432Sbostic		unput(us, addr, m, next_buf);
901*45432Sbostic		if (us->us_oactive == 0){
902*45432Sbostic			unstart(us, addr, next_buf);
903*45432Sbostic		}
904*45432Sbostic#ifdef ATR
905*45432Sbostic		restore_window(old_window);
906*45432Sbostic#endif ATR
907*45432Sbostic	}
908*45432Sbostic	else {
909*45432Sbostic		IF_ENQUEUE(&ifp->if_snd, m);
910*45432Sbostic	}
911*45432Sbostic	splx(s);
912*45432Sbostic	return(0);
913*45432Sbosticqfull:
914*45432Sbostic	m0 = m;
915*45432Sbostic	splx(s);
916*45432Sbosticbad:
917*45432Sbostic	m_freem(m0);
918*45432Sbostic	return(error);
919*45432Sbostic}
920*45432Sbostic
921*45432Sbostic/*
922*45432Sbostic *  unput -  copy packet from an  mbuf chain to one of the adapter's
923*45432Sbostic *  transmit buffers.  the packet is extended to the minimum legal
924*45432Sbostic *  size if necessary.  the extra bytes could be zeroed out to improve
925*45432Sbostic *  security but are not to maximize performance.
926*45432Sbostic */
927*45432Sbosticunput(us, addr, m, xbuf)
928*45432Sbostic	struct un_softc *us;
929*45432Sbostic	struct undevice *addr;
930*45432Sbostic	register struct mbuf *m;
931*45432Sbostic	register int xbuf;
932*45432Sbostic{
933*45432Sbostic	register unsigned off;
934*45432Sbostic	register struct mbuf *mp;
935*45432Sbostic	register char *bp;
936*45432Sbostic
937*45432Sbostic	/*
938*45432Sbostic	 *  compute starting address in transmit buffer.  packets must be
939*45432Sbostic	 *  "end_aligned".
940*45432Sbostic	 */
941*45432Sbostic	for (off = UN_XBSIZE, mp = m; mp; mp = mp->m_next){
942*45432Sbostic		off -= mp->m_len;
943*45432Sbostic	}
944*45432Sbostic	if (UN_XBSIZE - off < ETHERMIN + sizeof(struct ether_header)){
945*45432Sbostic		/*  packet too short => extend it */
946*45432Sbostic		off = UN_XBSIZE - ETHERMIN - sizeof(struct ether_header);
947*45432Sbostic	}
948*45432Sbostic	if (xbuf == 1){		/* use the second buffer */
949*45432Sbostic		off += UN_XBSIZE;	/* the 2 buffers are adjacent */
950*45432Sbostic	}
951*45432Sbostic	bp = ((char *)(addr->un_xmtbuf)) + off;
952*45432Sbostic	for (mp = m; mp; mp = mp->m_next){
953*45432Sbostic		register unsigned len = mp->m_len;
954*45432Sbostic
955*45432Sbostic		bcopyout(mtod(mp, char *), bp, len);
956*45432Sbostic		bp += len;
957*45432Sbostic	}
958*45432Sbostic	/* save starting address so interrupt handler can find it */
959*45432Sbostic	us->us_xstart[xbuf] = off;  /* start address to be passed to adapter */
960*45432Sbostic	us->us_xfull[xbuf] = 1;	/* mark buffer full */
961*45432Sbostic	m_freem(m);
962*45432Sbostic}
963*45432Sbostic
964*45432Sbostic/*
965*45432Sbostic *  unget - copy packet from adapter's receive buffers into a chain of mbufs
966*45432Sbostic *
967*45432Sbostic */
968*45432Sbosticstruct mbuf *
969*45432Sbosticunget(addr, unbuf, totlen, off0, ifp)
970*45432Sbostic	struct undevice *addr;
971*45432Sbostic	char *unbuf;
972*45432Sbostic	register int totlen;
973*45432Sbostic	int off0;
974*45432Sbostic	struct ifnet *ifp;
975*45432Sbostic{
976*45432Sbostic	register struct mbuf *m;
977*45432Sbostic	struct mbuf *top = 0;
978*45432Sbostic	register struct mbuf **mp = &top;
979*45432Sbostic	register int off = off0;
980*45432Sbostic	register int len;
981*45432Sbostic	register char *cp;
982*45432Sbostic#ifdef	ISO
983*45432Sbostic	int		copied_snpa = 0;
984*45432Sbostic#endif	ISO
985*45432Sbostic
986*45432Sbostic	cp = unbuf + sizeof(struct ether_header);
987*45432Sbostic	while (totlen > 0){
988*45432Sbostic		char *mcp;
989*45432Sbostic
990*45432Sbostic		MGET(m, M_DONTWAIT, MT_DATA);
991*45432Sbostic		if (m == 0)
992*45432Sbostic			goto bad;
993*45432Sbostic		if (off){	/* trailer exists */
994*45432Sbostic			len = totlen - off;
995*45432Sbostic			cp = unbuf + sizeof(struct ether_header) + off;
996*45432Sbostic		} else
997*45432Sbostic			len = totlen;
998*45432Sbostic#ifdef	ISO
999*45432Sbostic		if (!copied_snpa)
1000*45432Sbostic			len += sizeof(struct snpa_hdr);
1001*45432Sbostic#else	ISO
1002*45432Sbostic		if (ifp)
1003*45432Sbostic			len += sizeof(ifp);
1004*45432Sbostic#endif	ISO
1005*45432Sbostic		if (len >= NBPG){
1006*45432Sbostic			MCLGET(m);
1007*45432Sbostic			if (m->m_len == CLBYTES)
1008*45432Sbostic				m->m_len = len = MIN(len, CLBYTES);
1009*45432Sbostic			else
1010*45432Sbostic				m->m_len = len = MIN(MLEN, len);
1011*45432Sbostic		} else {
1012*45432Sbostic			m->m_len = len = MIN(MLEN, len);
1013*45432Sbostic			m->m_off = MMINOFF;
1014*45432Sbostic		}
1015*45432Sbostic		mcp = mtod(m, char *);
1016*45432Sbostic#ifdef	ISO
1017*45432Sbostic		if (!copied_snpa) {
1018*45432Sbostic			/*
1019*45432Sbostic			 *	Prepend snpa_hdr to first mbuf
1020*45432Sbostic			 *	The hardcoded 12 below refers to the length of the dhost
1021*45432Sbostic			 *	and shost fields. We recklessly assume
1022*45432Sbostic			 *	the order of dhost,shost in the snpa_hdr is the same
1023*45432Sbostic			 *	as the order in the ether_header.
1024*45432Sbostic			 */
1025*45432Sbostic			struct snpa_hdr		*sh = (struct snpa_hdr *)mcp;
1026*45432Sbostic			struct ether_header	*eh = (struct ether_header *)unbuf;
1027*45432Sbostic
1028*45432Sbostic			bcopy((char *) &ifp, (caddr_t)&sh->snh_ifp, sizeof(ifp));
1029*45432Sbostic			bcopy((caddr_t)eh, (caddr_t)sh->snh_dhost, 12);
1030*45432Sbostic			mcp += sizeof(struct snpa_hdr);
1031*45432Sbostic			len -= sizeof(struct snpa_hdr);
1032*45432Sbostic			copied_snpa = 1;
1033*45432Sbostic		}
1034*45432Sbostic#else	ISO
1035*45432Sbostic		if (ifp){
1036*45432Sbostic			/* prepend ifp to first mbuf */
1037*45432Sbostic			/*
1038*45432Sbostic			 * bcopy is used since since word moves must
1039*45432Sbostic			 * be on 4 byte boundaries on the RT PC
1040*45432Sbostic			 */
1041*45432Sbostic			bcopy((char *) &ifp, mcp, sizeof(ifp));
1042*45432Sbostic			mcp += sizeof(ifp);
1043*45432Sbostic			len -= sizeof(ifp);
1044*45432Sbostic			ifp = (struct ifnet *) 0;
1045*45432Sbostic		}
1046*45432Sbostic#endif	ISO
1047*45432Sbostic		unbcopy(addr, cp, mcp, len);
1048*45432Sbostic		cp += len;
1049*45432Sbostic		*mp = m;
1050*45432Sbostic		mp = &m->m_next;
1051*45432Sbostic		if (off == 0){
1052*45432Sbostic			totlen -= len;
1053*45432Sbostic			continue;
1054*45432Sbostic		}
1055*45432Sbostic		off += len;
1056*45432Sbostic		if (off == totlen){
1057*45432Sbostic			cp = unbuf + sizeof(struct ether_header);
1058*45432Sbostic			off = 0;
1059*45432Sbostic			totlen = off0;
1060*45432Sbostic		}
1061*45432Sbostic	}
1062*45432Sbostic	return(top);
1063*45432Sbosticbad:
1064*45432Sbostic	m_freem(top);
1065*45432Sbostic	return(0);
1066*45432Sbostic}
1067*45432Sbostic
1068*45432Sbostic
1069*45432Sbostic/*
1070*45432Sbostic *  ioctl - process an ioctl request.
1071*45432Sbostic */
1072*45432Sbosticunioctl(ifp, cmd, data)
1073*45432Sbostic	register struct ifnet *ifp;
1074*45432Sbostic	register int cmd;
1075*45432Sbostic	register caddr_t data;
1076*45432Sbostic{
1077*45432Sbostic	register struct ifaddr *ifa = (struct ifaddr *)data;
1078*45432Sbostic	register int s = splimp();
1079*45432Sbostic	register int error = 0;
1080*45432Sbostic
1081*45432Sbostic	switch (cmd){
1082*45432Sbostic	case SIOCSIFADDR:
1083*45432Sbostic		ifp->if_flags |= IFF_UP;
1084*45432Sbostic
1085*45432Sbostic		switch (ifa->ifa_addr.sa_family){
1086*45432Sbostic#ifdef INET
1087*45432Sbostic		case AF_INET:
1088*45432Sbostic			uninit(ifp->if_unit);	/* before arpwhohas */
1089*45432Sbostic			((struct arpcom *) ifp)->ac_ipaddr =
1090*45432Sbostic			  IA_SIN(ifa)->sin_addr;
1091*45432Sbostic			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
1092*45432Sbostic			break;
1093*45432Sbostic#endif INET
1094*45432Sbostic#ifdef NS
1095*45432Sbostic		case AF_NS:
1096*45432Sbostic		    {
1097*45432Sbostic			struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
1098*45432Sbostic			struct un_softc *us = &un_softc[ifp->if_unit];
1099*45432Sbostic
1100*45432Sbostic			if (ns_nullhost(*ina))
1101*45432Sbostic				ina->x_host = *(union ns_host *)(us->us_addr);
1102*45432Sbostic			else {
1103*45432Sbostic				ifp->if_flags &= ~IFF_RUNNING;
1104*45432Sbostic				bcopy((caddr_t) ina->x_host.c_host,
1105*45432Sbostic				  (caddr_t) us->us_addr, sizeof(us->us_addr));
1106*45432Sbostic				/*
1107*45432Sbostic				 *  the uninit will set the hardware address
1108*45432Sbostic				 *  since the IFF_RUNNING flag is off
1109*45432Sbostic				 */
1110*45432Sbostic			}
1111*45432Sbostic			uninit(ifp->if_unit);
1112*45432Sbostic			break;
1113*45432Sbostic		    }
1114*45432Sbostic#endif NS
1115*45432Sbostic		default:
1116*45432Sbostic			uninit(ifp->if_unit);
1117*45432Sbostic			break;
1118*45432Sbostic		}
1119*45432Sbostic		break;
1120*45432Sbostic	case SIOCSIFFLAGS:
1121*45432Sbostic		if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags &
1122*45432Sbostic		  IFF_RUNNING){
1123*45432Sbostic#ifdef ATR
1124*45432Sbostic			int old_window;
1125*45432Sbostic#endif ATR
1126*45432Sbostic			struct undevice *addr;
1127*45432Sbostic
1128*45432Sbostic			addr = (struct undevice *) uninfo[ifp->if_unit]->
1129*45432Sbostic				iod_addr;
1130*45432Sbostic#ifdef ATR
1131*45432Sbostic			move_window(old_window, addr);
1132*45432Sbostic#endif ATR
1133*45432Sbostic			(void) unzap((struct undevice *) addr);
1134*45432Sbostic			ifp->if_flags &= ~IFF_RUNNING;
1135*45432Sbostic#ifdef ATR
1136*45432Sbostic			restore_window(old_window);
1137*45432Sbostic#endif ATR
1138*45432Sbostic		} else if (ifp->if_flags & IFF_UP && (ifp->if_flags &
1139*45432Sbostic		  IFF_RUNNING) == 0)
1140*45432Sbostic			uninit(ifp->if_unit);
1141*45432Sbostic		break;
1142*45432Sbostic	default:
1143*45432Sbostic		error = EINVAL;
1144*45432Sbostic	}
1145*45432Sbostic	splx(s);
1146*45432Sbostic	return(error);
1147*45432Sbostic}
1148*45432Sbostic
1149*45432Sbostic/*
1150*45432Sbostic *  unzap - initialize adapter but don't enable it.
1151*45432Sbostic *  returns page number of next receive page to be used.
1152*45432Sbostic */
1153*45432Sbosticunzap(addr)
1154*45432Sbostic	register struct undevice *addr;
1155*45432Sbostic{
1156*45432Sbostic	register int next;
1157*45432Sbostic
1158*45432Sbostic	MM_OUT(&addr->un_csr, 0);		/* disable interrupts */
1159*45432Sbostic	MM_OUT(&addr->un_edlc.reset, RESET_ON);
1160*45432Sbostic		/* set reset bit while init'ing */
1161*45432Sbostic	MM_OUT(&addr->un_edlc.rstat, RS_CLEAR);
1162*45432Sbostic	MM_OUT(&addr->un_edlc.xstat, XS_CLEAR);
1163*45432Sbostic	MM_OUT(&addr->un_edlc.rmask, 0);
1164*45432Sbostic	MM_OUT(&addr->un_edlc.xmask, 0);
1165*45432Sbostic	MM_OUT(&addr->un_edlc.rmode, RM_NORMAL);
1166*45432Sbostic	/*
1167*45432Sbostic	 *  the next line puts the transmitter in loopback mode so
1168*45432Sbostic	 *  that a spurious packet is not sent when the reset bit is
1169*45432Sbostic	 *  cleared.
1170*45432Sbostic	 */
1171*45432Sbostic	MM_OUT(&addr->un_edlc.tmode, TM_NORMAL - TM_LBC);
1172*45432Sbostic	MM_OUT(&addr->un_edlc.reset, RESET_OFF); /* clear reset bit */
1173*45432Sbostic	/*
1174*45432Sbostic	 *  clear the receive buffers.  assign the value in the empty
1175*45432Sbostic	 *  page pointer to the full page pointer and clear the packet
1176*45432Sbostic	 *  available flag.
1177*45432Sbostic	 */
1178*45432Sbostic	next = MM_IN(&addr->un_fppepp) & UN_PAGE_MASK;
1179*45432Sbostic		/* clears the IKSYDK flag */
1180*45432Sbostic	MM_OUT(&addr->un_fppepp, next);		/* fpp = epp */
1181*45432Sbostic	UN_CLRPAV(addr);		/* clear the PAV flag */
1182*45432Sbostic	MM_OUT(&addr->un_edlc.tmode, TM_NORMAL);
1183*45432Sbostic		/* put transmitter in normal mode */
1184*45432Sbostic	DEBUGF(undebug & 0x2, printf("unzap: zzzzapped!\n");)
1185*45432Sbostic	return(next);
1186*45432Sbostic}
1187*45432Sbostic
1188*45432Sbostic/*
1189*45432Sbostic *  unupdatefpp - update adapter's full page pointer and clear packet available
1190*45432Sbostic *  flag if appropriate
1191*45432Sbostic */
1192*45432Sbosticunupdatefpp(addr, nextpage)
1193*45432Sbostic	register struct undevice *addr;
1194*45432Sbostic	register int nextpage;
1195*45432Sbostic{
1196*45432Sbostic	if (nextpage == /* EPP */ (MM_IN(&addr->un_fppepp) & UN_PAGE_MASK))
1197*45432Sbostic		UN_CLRPAV(addr);
1198*45432Sbostic	MM_OUT(&addr->un_fppepp, nextpage);	/* set FPP */
1199*45432Sbostic}
1200*45432Sbostic
1201*45432Sbostic/*
1202*45432Sbostic *  unbcopy - similar to bcopy but can deal with packets that wrap
1203*45432Sbostic *  around from the high end of the adapter's receive buffer to the
1204*45432Sbostic *  low end
1205*45432Sbostic */
1206*45432Sbosticunbcopy(addr, from, to, len)
1207*45432Sbostic	register struct undevice *addr;
1208*45432Sbostic	register char *from;
1209*45432Sbostic	register char *to;
1210*45432Sbostic	register int len;
1211*45432Sbostic{
1212*45432Sbostic	register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE];
1213*45432Sbostic	register int n;
1214*45432Sbostic
1215*45432Sbostic	if (from + len <= high_end){
1216*45432Sbostic		bcopyin(from, to, len);
1217*45432Sbostic	}
1218*45432Sbostic	else if (from >= high_end){
1219*45432Sbostic		from -= sizeof(addr->un_rcvbuf);
1220*45432Sbostic		bcopyin(from, to, len);
1221*45432Sbostic	} else {
1222*45432Sbostic		n = high_end - from;
1223*45432Sbostic		bcopyin(from, to, n);
1224*45432Sbostic		to += n;
1225*45432Sbostic		bcopyin((char *)addr->un_rcvbuf, to, len - n);
1226*45432Sbostic	}
1227*45432Sbostic}
1228*45432Sbostic
1229*45432Sbostic/*
1230*45432Sbostic *  ungetushortatoff - return the u_short at offset in the received packet,
1231*45432Sbostic *  handling wrap-around in the receive buffer and conversion between network
1232*45432Sbostic *  and host formats as necessary.
1233*45432Sbostic */
1234*45432Sbosticu_short ungetushortatoff(addr, eh, off)
1235*45432Sbostic	register struct undevice *addr;
1236*45432Sbostic	register struct ether_header *eh;
1237*45432Sbostic	register int off;
1238*45432Sbostic{
1239*45432Sbostic	register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE];
1240*45432Sbostic	register char *p;
1241*45432Sbostic
1242*45432Sbostic	p = (caddr_t)(eh + 1) + off;
1243*45432Sbostic	if (p >= high_end){
1244*45432Sbostic		p -= sizeof(addr->un_rcvbuf);
1245*45432Sbostic	}
1246*45432Sbostic	return(ntohs((u_short) MM_INW(p)));
1247*45432Sbostic}
1248*45432Sbostic
1249*45432Sbostic/*
1250*45432Sbostic *  unprintethaddr - print an ethernet address
1251*45432Sbostic */
1252*45432Sbosticunprintethaddr(p)
1253*45432Sbostic	register char *p;
1254*45432Sbostic{
1255*45432Sbostic	register int i;
1256*45432Sbostic
1257*45432Sbostic	for (i = 0; i < ETH_ADDR_SIZE; i++){
1258*45432Sbostic		if (i != 0) printf(":");
1259*45432Sbostic		printf("%x", *p++);
1260*45432Sbostic	}
1261*45432Sbostic}
1262*45432Sbostic
1263*45432Sbostic#endif NUN > 0
1264