xref: /netbsd-src/sys/arch/sun3/dev/if_le.c (revision 38023541164cff097d5fadec63134189b1453b8c)
1 /*
2  * Copyright (c) 1982, 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	from: @(#)if_le.c	7.6 (Berkeley) 5/8/91
34  *	if_le.c,v 1.2 1993/05/22 07:56:23 cgd Exp
35  */
36 
37 #include "bpfilter.h"
38 
39 /*
40  * AMD 7990 LANCE
41  *
42  * This driver will generate and accept tailer encapsulated packets even
43  * though it buys us nothing.  The motivation was to avoid incompatibilities
44  * with VAXen, SUNs, and others that handle and benefit from them.
45  * This reasoning is dubious.
46  */
47 #include "sys/param.h"
48 #include "sys/systm.h"
49 #include "sys/mbuf.h"
50 #include "sys/buf.h"
51 #include "sys/protosw.h"
52 #include "sys/socket.h"
53 #include "sys/syslog.h"
54 #include "sys/ioctl.h"
55 #include "sys/errno.h"
56 #include "sys/device.h"
57 
58 #include "net/if.h"
59 #include "net/netisr.h"
60 #include "net/route.h"
61 
62 #ifdef INET
63 #include "netinet/in.h"
64 #include "netinet/in_systm.h"
65 #include "netinet/in_var.h"
66 #include "netinet/ip.h"
67 #include "netinet/if_ether.h"
68 #endif
69 
70 #ifdef NS
71 #include "netns/ns.h"
72 #include "netns/ns_if.h"
73 #endif
74 
75 #ifdef RMP
76 #include "netrmp/rmp.h"
77 #include "netrmp/rmp_var.h"
78 #endif
79 
80 #include "machine/autoconf.h"
81 
82 #include "if_lereg.h"
83 
84 #if NBPFILTER > 0
85 #include "../net/bpf.h"
86 #include "../net/bpfdesc.h"
87 #endif
88 
89 #include "if_le.h"
90 #include "if_le_subr.h"
91 
92 int	ledebug = 1;		/* console error messages */
93 
94 int	leintr(), leioctl(), ether_output();
95 void lestart(), leinit();
96 struct	mbuf *leget();
97 extern	struct ifnet loif;
98 
99 /* access LANCE registers */
100 
101 void leattach __P((struct device *, struct device *, void *));
102 int lematch __P((struct device *, struct cfdata *, void *args));
103 
104 struct cfdriver lecd =
105 { NULL, "le", lematch, leattach, DV_DULL, sizeof(struct le_softc), 0};
106 
107 #define ISQUADALIGN(a) ((a & 0x3) == 0)
108 
109 int lematch(parent, cf, args)
110      struct device *parent;
111      struct cfdata *cf;
112      void *args;
113 {
114     return le_machdep_match(parent, cf, args);
115 }
116 /*
117  * Interface exists: make available by filling in network interface
118  * record.  System will initialize the interface when it is ready
119  * to accept packets.
120  */
121 void leattach(parent, self, args)
122      struct device *parent;
123      struct device *self;
124      void *args;
125 {
126 	register struct lereg2 *ler2;
127 	unsigned int a;
128 	struct le_softc *le = (struct le_softc *) self;
129 	struct ifnet *ifp = &le->sc_if;
130 	char *cp;
131 	int i, unit;
132 
133 	unit = le->sc_dev.dv_unit;
134 	if (le_machdep_attach(parent, self, args)) {
135 	    printf(": bad attach??\n");
136 	    return;
137 	}
138 	ler2 = le->sc_r2;
139 	printf(": ether address %s\n", ether_sprintf(le->sc_addr));
140 
141 	/*
142 	 * Setup for transmit/receive
143 	 */
144 	ler2->ler2_mode = LE_MODE;
145 	ler2->ler2_padr[0] = le->sc_addr[1];
146 	ler2->ler2_padr[1] = le->sc_addr[0];
147 	ler2->ler2_padr[2] = le->sc_addr[3];
148 	ler2->ler2_padr[3] = le->sc_addr[2];
149 	ler2->ler2_padr[4] = le->sc_addr[5];
150 	ler2->ler2_padr[5] = le->sc_addr[4];
151 #ifdef RMP
152 	/*
153 	 * Set up logical addr filter to accept multicast 9:0:9:0:0:4
154 	 * This should be an ioctl() to the driver.  (XXX)
155 	 */
156 	ler2->ler2_ladrf0 = 0x00100000;
157 	ler2->ler2_ladrf1 = 0x0;
158 #else
159 	ler2->ler2_ladrf0 = 0;
160 	ler2->ler2_ladrf1 = 0;
161 #endif
162 	a = LANCE_ADDR(ler2->ler2_rmd);
163 	if (!ISQUADALIGN(a))
164 	    panic("rdra not quad aligned");
165 	ler2->ler2_rlen = LE_RLEN | (a >> 16);
166 	ler2->ler2_rdra = a & LE_ADDR_LOW_MASK;
167 	a = LANCE_ADDR(ler2->ler2_tmd);
168 	if (!ISQUADALIGN(a))
169 	    panic("tdra not quad aligned");
170 	ler2->ler2_tlen = LE_TLEN | (a >> 16);
171 	ler2->ler2_tdra = a & LE_ADDR_LOW_MASK;
172 
173 	ifp->if_unit = unit;
174 	ifp->if_name = "le";
175 	ifp->if_mtu = ETHERMTU;
176 	ifp->if_ioctl = leioctl;
177 	ifp->if_output = ether_output;
178 	ifp->if_start = lestart;
179 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
180 #if NBPFILTER > 0
181 	bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
182 #endif
183 	if_attach(ifp);
184 }
185 
186 ledrinit(ler2)
187 	register struct lereg2 *ler2;
188 {
189         unsigned int a;
190 	register int i;
191 
192 	for (i = 0; i < LERBUF; i++) {
193 	        a = LANCE_ADDR(&ler2->ler2_rbuf[i][0]);
194 #if 0
195 		if (!ISQUADALIGN(a))
196 		    panic("rbuf not quad aligned");
197 #endif
198 		ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK;
199 		ler2->ler2_rmd[i].rmd1_bits = LE_OWN;
200 		ler2->ler2_rmd[i].rmd1_hadr = a >> 16;
201 		ler2->ler2_rmd[i].rmd2 = -LEMTU;
202 		ler2->ler2_rmd[i].rmd3 = 0;
203 	}
204 	for (i = 0; i < LETBUF; i++) {
205 	        a = LANCE_ADDR(&ler2->ler2_tbuf[i][0]);
206 #if 0
207 		if (!ISQUADALIGN(a))
208 		    panic("rbuf not quad aligned");
209 #endif
210 		ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK;
211 		ler2->ler2_tmd[i].tmd1_bits = 0;
212 		ler2->ler2_tmd[i].tmd1_hadr = a >> 16;
213 		ler2->ler2_tmd[i].tmd2 = 0;
214 		ler2->ler2_tmd[i].tmd3 = 0;
215 	}
216 }
217 
218 lereset(unit)
219 	register int unit;
220 {
221         register struct le_softc *le = (struct le_softc *) lecd.cd_devs[unit];
222 	register struct lereg1 *ler1 = le->sc_r1;
223 	register struct lereg2 *ler2 = le->sc_r2;
224 	unsigned int a;
225 	register int timo = 100000;
226 	register int stat;
227 
228 #ifdef lint
229 	stat = unit;
230 #endif
231 #if NBPFILTER > 0
232 	if (le->sc_if.if_flags & IFF_PROMISC)
233 		/* set the promiscuous bit */
234 		le->sc_r2->ler2_mode = LE_MODE|0x8000;
235 	else
236 		le->sc_r2->ler2_mode = LE_MODE;
237 #endif
238 	if (ledebug)
239 	    printf("le: resetting unit %d, reg %x, ram %x\n",
240 		   unit, le->sc_r1, le->sc_r2);
241 	LERDWR(le, LE_CSR0, ler1->ler1_rap);
242 	LERDWR(le, LE_STOP, ler1->ler1_rdp);
243 	ledrinit(le->sc_r2);
244 	le->sc_rmd = 0;
245 	LERDWR(le, LE_CSR1, ler1->ler1_rap);
246 	a = LANCE_ADDR(ler2);
247 	LERDWR(le, a & LE_ADDR_LOW_MASK, ler1->ler1_rdp);
248 	LERDWR(le, LE_CSR2, ler1->ler1_rap);
249 	LERDWR(le, a >> 16, ler1->ler1_rdp);
250 	LERDWR(le, LE_CSR0, ler1->ler1_rap);
251 	LERDWR(le, LE_INIT, ler1->ler1_rdp);
252 	do {
253 		if (--timo == 0) {
254 			printf("le%d: init timeout, stat = 0x%x\n",
255 			       unit, stat);
256 			break;
257 		}
258 		LERDWR(le, ler1->ler1_rdp, stat);
259 	} while ((stat & LE_IDON) == 0);
260 	LERDWR(le, LE_STOP, ler1->ler1_rdp);
261 	LERDWR(le, LE_CSR3, ler1->ler1_rap);
262 	LERDWR(le, LE_BSWP, ler1->ler1_rdp);
263 	LERDWR(le, LE_CSR0, ler1->ler1_rap);
264 	LERDWR(le, LE_STRT | LE_INEA, ler1->ler1_rdp);
265 	le->sc_if.if_flags &= ~IFF_OACTIVE;
266 }
267 
268 /*
269  * Initialization of interface
270  */
271 void leinit(unit)
272 	int unit;
273 {
274 	struct le_softc *le = lecd.cd_devs[unit];
275 	register struct ifnet *ifp = &le->sc_if;
276 	int s;
277 
278 	/* not yet, if address still unknown */
279 	if (ifp->if_addrlist == (struct ifaddr *)0)
280 		return;
281 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
282 		s = splimp();
283 		if (ledebug)
284 		    printf("le: initializing unit %d, reg %x, ram %x\n",
285 			   unit, le->sc_r1, le->sc_r2);
286 		ifp->if_flags |= IFF_RUNNING;
287 		lereset(unit);
288 	        (void) lestart(ifp);
289 		splx(s);
290 	}
291 }
292 
293 /*
294  * Start output on interface.  Get another datagram to send
295  * off of the interface queue, and copy it to the interface
296  * before starting the output.
297  */
298 void lestart(ifp)
299 	struct ifnet *ifp;
300 {
301 	register struct le_softc *le = lecd.cd_devs[ifp->if_unit];
302 	register struct letmd *tmd;
303 	register struct mbuf *m;
304 	int len;
305 
306 	if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
307 		return;
308 	IF_DEQUEUE(&le->sc_if.if_snd, m);
309 	if (m == 0)
310 		return;
311 	len = leput(le->sc_r2->ler2_tbuf[0], m);
312 #if NBPFILTER > 0
313 	/*
314 	 * If bpf is listening on this interface, let it
315 	 * see the packet before we commit it to the wire.
316 	 */
317 	if (le->sc_bpf)
318                 bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[0], len);
319 #endif
320 	tmd = le->sc_r2->ler2_tmd;
321 	tmd->tmd3 = 0;
322 	tmd->tmd2 = -len;
323 	tmd->tmd1_bits = LE_OWN | LE_STP | LE_ENP;
324 	le->sc_if.if_flags |= IFF_OACTIVE;
325 }
326 
327 leintr(unit)
328 	register int unit;
329 {
330 	register struct le_softc *le = lecd.cd_devs[unit];
331 	register struct lereg1 *ler1;
332 	register int stat;
333 
334 	le_machdep_intrcheck(le, unit);
335 	ler1 = le->sc_r1;
336 	LERDWR(le, ler1->ler1_rdp, stat);
337 	if (ledebug)
338 	    printf("[le%d: stat %b]", unit, stat, LE_STATUS_BITS);
339 	if (stat & LE_SERR) {
340 		leerror(unit, stat);
341 		if (stat & LE_MERR) {
342 			le->sc_merr++;
343 			lereset(unit);
344 			return(1);
345 		}
346 		if (stat & LE_BABL)
347 			le->sc_babl++;
348 		if (stat & LE_CERR)
349 			le->sc_cerr++;
350 		if (stat & LE_MISS)
351 			le->sc_miss++;
352 		LERDWR(le, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp);
353 	}
354 	if ((stat & LE_RXON) == 0) {
355 		le->sc_rxoff++;
356 		lereset(unit);
357 		return(1);
358 	}
359 	if ((stat & LE_TXON) == 0) {
360 		le->sc_txoff++;
361 		lereset(unit);
362 		return(1);
363 	}
364 	if (stat & LE_RINT) {
365 		/* interrupt is cleared in lerint */
366 		lerint(unit);
367 	}
368 	if (stat & LE_TINT) {
369 		LERDWR(le, LE_TINT|LE_INEA, ler1->ler1_rdp);
370 		lexint(unit);
371 	}
372 	return(1);
373 }
374 
375 /*
376  * Ethernet interface transmitter interrupt.
377  * Start another output if more data to send.
378  */
379 lexint(unit)
380 	register int unit;
381 {
382 	register struct le_softc *le = lecd.cd_devs[unit];
383 	register struct letmd *tmd = le->sc_r2->ler2_tmd;
384 
385 	if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
386 		le->sc_xint++;
387 		return;
388 	}
389 	if (tmd->tmd1_bits & LE_OWN) {
390 		le->sc_xown++;
391 		return;
392 	}
393 	if (tmd->tmd1_bits & LE_ERR) {
394 err:
395 		lexerror(unit);
396 		le->sc_if.if_oerrors++;
397 		if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) {
398 			le->sc_uflo++;
399 			lereset(unit);
400 		}
401 		else if (tmd->tmd3 & LE_LCOL)
402 			le->sc_if.if_collisions++;
403 		else if (tmd->tmd3 & LE_RTRY)
404 			le->sc_if.if_collisions += 16;
405 	}
406 	else if (tmd->tmd3 & LE_TBUFF)
407 		/* XXX documentation says BUFF not included in ERR */
408 		goto err;
409 	else if (tmd->tmd1_bits & LE_ONE)
410 		le->sc_if.if_collisions++;
411 	else if (tmd->tmd1_bits & LE_MORE)
412 		/* what is the real number? */
413 		le->sc_if.if_collisions += 2;
414 	else
415 		le->sc_if.if_opackets++;
416 	le->sc_if.if_flags &= ~IFF_OACTIVE;
417 	(void) lestart(&le->sc_if);
418 }
419 
420 #define	LENEXTRMP \
421 	if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd
422 
423 /*
424  * Ethernet interface receiver interrupt.
425  * If input error just drop packet.
426  * Decapsulate packet based on type and pass to type specific
427  * higher-level input routine.
428  */
429 lerint(unit)
430 	int unit;
431 {
432 	register struct le_softc *le = lecd.cd_devs[unit];
433 	register int bix = le->sc_rmd;
434 	register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix];
435 
436 	/*
437 	 * Out of sync with hardware, should never happen?
438 	 */
439 	if (rmd->rmd1_bits & LE_OWN) {
440 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
441 		return;
442 	}
443 
444 	/*
445 	 * Process all buffers with valid data
446 	 */
447 	while ((rmd->rmd1_bits & LE_OWN) == 0) {
448 		int len = rmd->rmd3;
449 
450 		/* Clear interrupt to avoid race condition */
451 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
452 
453 		if (rmd->rmd1_bits & LE_ERR) {
454 			le->sc_rmd = bix;
455 			lererror(unit, "bad packet");
456 			le->sc_if.if_ierrors++;
457 		} else if ((rmd->rmd1_bits & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
458 			/*
459 			 * Find the end of the packet so we can see how long
460 			 * it was.  We still throw it away.
461 			 */
462 			do {
463 				LERDWR(le->sc_r0, LE_RINT|LE_INEA,
464 				       le->sc_r1->ler1_rdp);
465 				rmd->rmd3 = 0;
466 				rmd->rmd1_bits = LE_OWN;
467 				LENEXTRMP;
468 			} while (!(rmd->rmd1_bits & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
469 			le->sc_rmd = bix;
470 			lererror(unit, "chained buffer");
471 			le->sc_rxlen++;
472 			/*
473 			 * If search terminated without successful completion
474 			 * we reset the hardware (conservative).
475 			 */
476 			if ((rmd->rmd1_bits & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
477 			    LE_ENP) {
478 				lereset(unit);
479 				return;
480 			}
481 		} else
482 			leread(unit, le->sc_r2->ler2_rbuf[bix], len);
483 		rmd->rmd3 = 0;
484 		rmd->rmd1_bits = LE_OWN;
485 		LENEXTRMP;
486 	}
487 	le->sc_rmd = bix;
488 }
489 
490 leread(unit, buf, len)
491 	int unit;
492 	char *buf;
493 	int len;
494 {
495 	register struct le_softc *le = lecd.cd_devs[unit];
496 	register struct ether_header *et;
497     	struct mbuf *m;
498 	int off, resid;
499 
500 	le->sc_if.if_ipackets++;
501 	et = (struct ether_header *)buf;
502 	et->ether_type = ntohs((u_short)et->ether_type);
503 	/* adjust input length to account for header and CRC */
504 	len = len - sizeof(struct ether_header) - 4;
505 
506 #ifdef RMP
507 	/*  (XXX)
508 	 *
509 	 *  If Ethernet Type field is < MaxPacketSize, we probably have
510 	 *  a IEEE802 packet here.  Make sure that the size is at least
511 	 *  that of the HP LLC.  Also do sanity checks on length of LLC
512 	 *  (old Ethernet Type field) and packet length.
513 	 *
514 	 *  Provided the above checks succeed, change `len' to reflect
515 	 *  the length of the LLC (i.e. et->ether_type) and change the
516 	 *  type field to ETHERTYPE_IEEE so we can switch() on it later.
517 	 *  Yes, this is a hack and will eventually be done "right".
518 	 */
519 	if (et->ether_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) &&
520 	    len >= et->ether_type && len >= IEEE802LEN_MIN) {
521 		len = et->ether_type;
522 		et->ether_type = ETHERTYPE_IEEE;	/* hack! */
523 	}
524 #endif
525 
526 #define	ledataaddr(et, off, type)	((type)(((caddr_t)((et)+1)+(off))))
527 	if (et->ether_type >= ETHERTYPE_TRAIL &&
528 	    et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
529 		off = (et->ether_type - ETHERTYPE_TRAIL) * 512;
530 		if (off >= ETHERMTU)
531 			return;		/* sanity */
532 		et->ether_type = ntohs(*ledataaddr(et, off, u_short *));
533 		resid = ntohs(*(ledataaddr(et, off+2, u_short *)));
534 		if (off + resid > len)
535 			return;		/* sanity */
536 		len = off + resid;
537 	} else
538 		off = 0;
539 
540 	if (len <= 0) {
541 		if (ledebug)
542 			log(LOG_WARNING,
543 			    "le%d: ierror(runt packet): from %s: len=%d\n",
544 			    unit, ether_sprintf(et->ether_shost), len);
545 		le->sc_runt++;
546 		le->sc_if.if_ierrors++;
547 		return;
548 	}
549 #if NBPFILTER > 0
550 	/*
551 	 * Check if there's a bpf filter listening on this interface.
552 	 * If so, hand off the raw packet to bpf, which must deal with
553 	 * trailers in its own way.
554 	 */
555 	if (le->sc_bpf) {
556 		bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header));
557 
558 		/*
559 		 * Note that the interface cannot be in promiscuous mode if
560 		 * there are no bpf listeners.  And if we are in promiscuous
561 		 * mode, we have to check if this packet is really ours.
562 		 *
563 		 * XXX This test does not support multicasts.
564 		 */
565 		if ((le->sc_if.if_flags & IFF_PROMISC)
566 		    && bcmp(et->ether_dhost, le->sc_addr,
567 			    sizeof(et->ether_dhost)) != 0
568 		    && bcmp(et->ether_dhost, etherbroadcastaddr,
569 			    sizeof(et->ether_dhost)) != 0)
570 			return;
571 	}
572 #endif
573 	/*
574 	 * Pull packet off interface.  Off is nonzero if packet
575 	 * has trailing header; leget will then force this header
576 	 * information to be at the front, but we still have to drop
577 	 * the type and length which are at the front of any trailer data.
578 	 */
579 	m = leget(buf, len, off, &le->sc_if);
580 	if (m == 0)
581 		return;
582 #ifdef RMP
583 	/*
584 	 * (XXX)
585 	 * This needs to be integrated with the ISO stuff in ether_input()
586 	 */
587 	if (et->ether_type == ETHERTYPE_IEEE) {
588 		/*
589 		 *  Snag the Logical Link Control header (IEEE 802.2).
590 		 */
591 		struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc);
592 
593 		/*
594 		 *  If the DSAP (and HP's extended DXSAP) indicate this
595 		 *  is an RMP packet, hand it to the raw input routine.
596 		 */
597 		if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) {
598 			static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT};
599 			static struct sockaddr rmp_src = {AF_RMP};
600 			static struct sockaddr rmp_dst = {AF_RMP};
601 
602 			bcopy(et->ether_shost, rmp_src.sa_data,
603 			      sizeof(et->ether_shost));
604 			bcopy(et->ether_dhost, rmp_dst.sa_data,
605 			      sizeof(et->ether_dhost));
606 
607 			raw_input(m, &rmp_sp, &rmp_src, &rmp_dst);
608 			return;
609 		}
610 	}
611 #endif
612 	ether_input(&le->sc_if, et, m);
613 }
614 
615 /*
616  * Routine to copy from mbuf chain to transmit
617  * buffer in board local memory.
618  */
619 leput(lebuf, m)
620 	register char *lebuf;
621 	register struct mbuf *m;
622 {
623 	register struct mbuf *mp;
624 	register int len, tlen = 0;
625 
626 	for (mp = m; mp; mp = mp->m_next) {
627 		len = mp->m_len;
628 		if (len == 0)
629 			continue;
630 		tlen += len;
631 		bcopy(mtod(mp, char *), lebuf, len);
632 		lebuf += len;
633 	}
634 	m_freem(m);
635 	if (tlen < LEMINSIZE) {
636 		bzero(lebuf, LEMINSIZE - tlen);
637 		tlen = LEMINSIZE;
638 	}
639 	return(tlen);
640 }
641 
642 /*
643  * Routine to copy from board local memory into mbufs.
644  */
645 struct mbuf *
646 leget(lebuf, totlen, off0, ifp)
647 	char *lebuf;
648 	int totlen, off0;
649 	struct ifnet *ifp;
650 {
651 	register struct mbuf *m;
652 	struct mbuf *top = 0, **mp = &top;
653 	register int off = off0, len;
654 	register char *cp;
655 	char *epkt;
656 
657 	lebuf += sizeof (struct ether_header);
658 	cp = lebuf;
659 	epkt = cp + totlen;
660 	if (off) {
661 		cp += off + 2 * sizeof(u_short);
662 		totlen -= 2 * sizeof(u_short);
663 	}
664 
665 	MGETHDR(m, M_DONTWAIT, MT_DATA);
666 	if (m == 0)
667 		return (0);
668 	m->m_pkthdr.rcvif = ifp;
669 	m->m_pkthdr.len = totlen;
670 	m->m_len = MHLEN;
671 
672 	while (totlen > 0) {
673 		if (top) {
674 			MGET(m, M_DONTWAIT, MT_DATA);
675 			if (m == 0) {
676 				m_freem(top);
677 				return (0);
678 			}
679 			m->m_len = MLEN;
680 		}
681 		len = min(totlen, epkt - cp);
682 		if (len >= MINCLSIZE) {
683 			MCLGET(m, M_DONTWAIT);
684 			if (m->m_flags & M_EXT)
685 				m->m_len = len = min(len, MCLBYTES);
686 			else
687 				len = m->m_len;
688 		} else {
689 			/*
690 			 * Place initial small packet/header at end of mbuf.
691 			 */
692 			if (len < m->m_len) {
693 				if (top == 0 && len + max_linkhdr <= m->m_len)
694 					m->m_data += max_linkhdr;
695 				m->m_len = len;
696 			} else
697 				len = m->m_len;
698 		}
699 		bcopy(cp, mtod(m, caddr_t), (unsigned)len);
700 		cp += len;
701 		*mp = m;
702 		mp = &m->m_next;
703 		totlen -= len;
704 		if (cp == epkt)
705 			cp = lebuf;
706 	}
707 	return (top);
708 }
709 
710 /*
711  * Process an ioctl request.
712  */
713 leioctl(ifp, cmd, data)
714 	register struct ifnet *ifp;
715 	int cmd;
716 	caddr_t data;
717 {
718 	register struct ifaddr *ifa = (struct ifaddr *)data;
719 	struct le_softc *le = (struct le_softc *) lecd.cd_devs[ifp->if_unit];
720 	struct lereg1 *ler1 = le->sc_r1;
721 	int s = splimp(), error = 0;
722 
723 	switch (cmd) {
724 
725 	case SIOCSIFADDR:
726 		ifp->if_flags |= IFF_UP;
727 		switch (ifa->ifa_addr->sa_family) {
728 #ifdef INET
729 		case AF_INET:
730 			leinit(ifp->if_unit);	/* before arpwhohas */
731 			((struct arpcom *)ifp)->ac_ipaddr =
732 				IA_SIN(ifa)->sin_addr;
733 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
734 			break;
735 #endif
736 #ifdef NS
737 		case AF_NS:
738 		    {
739 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
740 
741 			if (ns_nullhost(*ina))
742 				ina->x_host = *(union ns_host *)(le->sc_addr);
743 			else {
744 				/*
745 				 * The manual says we can't change the address
746 				 * while the receiver is armed,
747 				 * so reset everything
748 				 */
749 				ifp->if_flags &= ~IFF_RUNNING;
750 				bcopy((caddr_t)ina->x_host.c_host,
751 				    (caddr_t)le->sc_addr, sizeof(le->sc_addr));
752 			}
753 			leinit(ifp->if_unit); /* does le_setaddr() */
754 			break;
755 		    }
756 #endif
757 		default:
758 			leinit(ifp->if_unit);
759 			break;
760 		}
761 		break;
762 
763 	case SIOCSIFFLAGS:
764 		if ((ifp->if_flags & IFF_UP) == 0 &&
765 		    ifp->if_flags & IFF_RUNNING) {
766 			LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp);
767 			ifp->if_flags &= ~IFF_RUNNING;
768 		} else if (ifp->if_flags & IFF_UP &&
769 		    (ifp->if_flags & IFF_RUNNING) == 0)
770 			leinit(ifp->if_unit);
771 		/*
772 		 * If the state of the promiscuous bit changes, the interface
773 		 * must be reset to effect the change.
774 		 */
775 		if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) &&
776 		    (ifp->if_flags & IFF_RUNNING)) {
777 			le->sc_iflags = ifp->if_flags;
778 			lereset(ifp->if_unit);
779 			lestart(ifp);
780 		}
781 		break;
782 
783 	default:
784 		error = EINVAL;
785 	}
786 	splx(s);
787 	return (error);
788 }
789 
790 leerror(unit, stat)
791 	int unit;
792 	int stat;
793 {
794 	struct le_softc *le = NULL;
795 
796 
797 	if (!ledebug)
798 		return;
799 
800 	le = (struct le_softc *) lecd.cd_devs[unit];
801 	/*
802 	 * Not all transceivers implement heartbeat
803 	 * so we only log CERR once.
804 	 */
805 	if ((stat & LE_CERR) && le->sc_cerr)
806 		return;
807 	log(LOG_WARNING,
808 	    "le%d: error: stat=%b\n", unit,
809 	    stat,
810 	    LE_STATUS_BITS);
811 }
812 
813 lererror(unit, msg)
814 	int unit;
815 	char *msg;
816 {
817 	register struct le_softc *le = lecd.cd_devs[unit];
818 	register struct lermd *rmd;
819 	int len;
820 
821 	if (!ledebug)
822 		return;
823 
824 	rmd = &le->sc_r2->ler2_rmd[le->sc_rmd];
825 	len = rmd->rmd3;
826 	log(LOG_WARNING,
827 	    "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1_bits=%b\n",
828 	    unit, msg,
829 	    len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown",
830 	    le->sc_rmd, len,
831 	    rmd->rmd1_bits,
832 	    "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3RBUF\2STP\1ENP");
833 }
834 
835 lexerror(unit)
836 	int unit;
837 {
838 	register struct le_softc *le = lecd.cd_devs[unit];
839 	register struct letmd *tmd;
840 	int len;
841 
842 	if (!ledebug)
843 		return;
844 
845 	tmd = le->sc_r2->ler2_tmd;
846 	len = -tmd->tmd2;
847 	log(LOG_WARNING,
848 	    "le%d: oerror: to %s: buf=%d, len=%d, tmd1_bits=%b, tmd3=%b\n",
849 	    unit,
850 	    len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown",
851 	    0, len,
852 	    tmd->tmd1_bits,
853 	    "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP",
854 	    tmd->tmd3,
855 	    "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
856 }
857