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