xref: /netbsd-src/sys/arch/sun3/dev/if_le.c (revision ae1bfcddc410612bc8c58b807e1830becb69a24c)
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 = 0;		/* console error messages */
93 
94 int	leintr(), leioctl(), ether_output(), lestart();
95 void    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_ioctl = leioctl;
176 	ifp->if_output = ether_output;
177 	ifp->if_start = lestart;
178 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
179 #if NBPFILTER > 0
180 	bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
181 #endif
182 	if_attach(ifp);
183 	ether_ifattach(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 int 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 0;
308 	IF_DEQUEUE(&le->sc_if.if_snd, m);
309 	if (m == 0)
310 		return 0;
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 	return 0;
326 }
327 
328 leintr(unit)
329 	register int unit;
330 {
331 	register struct le_softc *le = lecd.cd_devs[unit];
332 	register struct lereg1 *ler1;
333 	register int stat;
334 
335 	le_machdep_intrcheck(le, unit);
336 	ler1 = le->sc_r1;
337 	LERDWR(le, ler1->ler1_rdp, stat);
338 	if (ledebug)
339 	    printf("[le%d: stat %b]\n", unit, stat, LE_STATUS_BITS);
340 	if (stat & LE_SERR) {
341 		leerror(unit, stat);
342 		if (stat & LE_MERR) {
343 			le->sc_merr++;
344 			lereset(unit);
345 			return(1);
346 		}
347 		if (stat & LE_BABL)
348 			le->sc_babl++;
349 		if (stat & LE_CERR)
350 			le->sc_cerr++;
351 		if (stat & LE_MISS)
352 			le->sc_miss++;
353 		LERDWR(le, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp);
354 	}
355 	if ((stat & LE_RXON) == 0) {
356 		le->sc_rxoff++;
357 		lereset(unit);
358 		return(1);
359 	}
360 	if ((stat & LE_TXON) == 0) {
361 		le->sc_txoff++;
362 		lereset(unit);
363 		return(1);
364 	}
365 	if (stat & LE_RINT) {
366 		/* interrupt is cleared in lerint */
367 		lerint(unit);
368 	}
369 	if (stat & LE_TINT) {
370 		LERDWR(le, LE_TINT|LE_INEA, ler1->ler1_rdp);
371 		lexint(unit);
372 	}
373 	return(1);
374 }
375 
376 /*
377  * Ethernet interface transmitter interrupt.
378  * Start another output if more data to send.
379  */
380 lexint(unit)
381 	register int unit;
382 {
383 	register struct le_softc *le = lecd.cd_devs[unit];
384 	register struct letmd *tmd = le->sc_r2->ler2_tmd;
385 
386 	if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
387 		le->sc_xint++;
388 		return;
389 	}
390 	if (tmd->tmd1_bits & LE_OWN) {
391 		le->sc_xown++;
392 		return;
393 	}
394 	if (tmd->tmd1_bits & LE_ERR) {
395 err:
396 		lexerror(unit);
397 		le->sc_if.if_oerrors++;
398 		if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) {
399 			le->sc_uflo++;
400 			lereset(unit);
401 		}
402 		else if (tmd->tmd3 & LE_LCOL)
403 			le->sc_if.if_collisions++;
404 		else if (tmd->tmd3 & LE_RTRY)
405 			le->sc_if.if_collisions += 16;
406 	}
407 	else if (tmd->tmd3 & LE_TBUFF)
408 		/* XXX documentation says BUFF not included in ERR */
409 		goto err;
410 	else if (tmd->tmd1_bits & LE_ONE)
411 		le->sc_if.if_collisions++;
412 	else if (tmd->tmd1_bits & LE_MORE)
413 		/* what is the real number? */
414 		le->sc_if.if_collisions += 2;
415 	else
416 		le->sc_if.if_opackets++;
417 	le->sc_if.if_flags &= ~IFF_OACTIVE;
418 	(void) lestart(&le->sc_if);
419 }
420 
421 #define	LENEXTRMP \
422 	if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd
423 
424 /*
425  * Ethernet interface receiver interrupt.
426  * If input error just drop packet.
427  * Decapsulate packet based on type and pass to type specific
428  * higher-level input routine.
429  */
430 lerint(unit)
431 	int unit;
432 {
433 	register struct le_softc *le = lecd.cd_devs[unit];
434 	register int bix = le->sc_rmd;
435 	register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix];
436 
437 	/*
438 	 * Out of sync with hardware, should never happen?
439 	 */
440 	if (rmd->rmd1_bits & LE_OWN) {
441 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
442 		return;
443 	}
444 
445 	/*
446 	 * Process all buffers with valid data
447 	 */
448 	while ((rmd->rmd1_bits & LE_OWN) == 0) {
449 		int len = rmd->rmd3;
450 
451 		/* Clear interrupt to avoid race condition */
452 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
453 
454 		if (rmd->rmd1_bits & LE_ERR) {
455 			le->sc_rmd = bix;
456 			lererror(unit, "bad packet");
457 			le->sc_if.if_ierrors++;
458 		} else if ((rmd->rmd1_bits & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
459 			/*
460 			 * Find the end of the packet so we can see how long
461 			 * it was.  We still throw it away.
462 			 */
463 			do {
464 				LERDWR(le->sc_r0, LE_RINT|LE_INEA,
465 				       le->sc_r1->ler1_rdp);
466 				rmd->rmd3 = 0;
467 				rmd->rmd1_bits = LE_OWN;
468 				LENEXTRMP;
469 			} while (!(rmd->rmd1_bits & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
470 			le->sc_rmd = bix;
471 			lererror(unit, "chained buffer");
472 			le->sc_rxlen++;
473 			/*
474 			 * If search terminated without successful completion
475 			 * we reset the hardware (conservative).
476 			 */
477 			if ((rmd->rmd1_bits & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
478 			    LE_ENP) {
479 				lereset(unit);
480 				return;
481 			}
482 		} else
483 			leread(unit, le->sc_r2->ler2_rbuf[bix], len);
484 		rmd->rmd3 = 0;
485 		rmd->rmd1_bits = LE_OWN;
486 		LENEXTRMP;
487 	}
488 	le->sc_rmd = bix;
489 }
490 
491 leread(unit, buf, len)
492 	int unit;
493 	char *buf;
494 	int len;
495 {
496 	register struct le_softc *le = lecd.cd_devs[unit];
497 	register struct ether_header *et;
498     	struct mbuf *m;
499 	int off, resid;
500 
501 	le->sc_if.if_ipackets++;
502 	et = (struct ether_header *)buf;
503 	et->ether_type = ntohs((u_short)et->ether_type);
504 	/* adjust input length to account for header and CRC */
505 	len = len - sizeof(struct ether_header) - 4;
506 
507 #ifdef RMP
508 	/*  (XXX)
509 	 *
510 	 *  If Ethernet Type field is < MaxPacketSize, we probably have
511 	 *  a IEEE802 packet here.  Make sure that the size is at least
512 	 *  that of the HP LLC.  Also do sanity checks on length of LLC
513 	 *  (old Ethernet Type field) and packet length.
514 	 *
515 	 *  Provided the above checks succeed, change `len' to reflect
516 	 *  the length of the LLC (i.e. et->ether_type) and change the
517 	 *  type field to ETHERTYPE_IEEE so we can switch() on it later.
518 	 *  Yes, this is a hack and will eventually be done "right".
519 	 */
520 	if (et->ether_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) &&
521 	    len >= et->ether_type && len >= IEEE802LEN_MIN) {
522 		len = et->ether_type;
523 		et->ether_type = ETHERTYPE_IEEE;	/* hack! */
524 	}
525 #endif
526 
527 #define	ledataaddr(et, off, type)	((type)(((caddr_t)((et)+1)+(off))))
528 	if (et->ether_type >= ETHERTYPE_TRAIL &&
529 	    et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
530 		off = (et->ether_type - ETHERTYPE_TRAIL) * 512;
531 		if (off >= ETHERMTU)
532 			return;		/* sanity */
533 		et->ether_type = ntohs(*ledataaddr(et, off, u_short *));
534 		resid = ntohs(*(ledataaddr(et, off+2, u_short *)));
535 		if (off + resid > len)
536 			return;		/* sanity */
537 		len = off + resid;
538 	} else
539 		off = 0;
540 
541 	if (len <= 0) {
542 		if (ledebug)
543 			log(LOG_WARNING,
544 			    "le%d: ierror(runt packet): from %s: len=%d\n",
545 			    unit, ether_sprintf(et->ether_shost), len);
546 		le->sc_runt++;
547 		le->sc_if.if_ierrors++;
548 		return;
549 	}
550 #if NBPFILTER > 0
551 	/*
552 	 * Check if there's a bpf filter listening on this interface.
553 	 * If so, hand off the raw packet to bpf, which must deal with
554 	 * trailers in its own way.
555 	 */
556 	if (le->sc_bpf) {
557 		bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header));
558 
559 		/*
560 		 * Note that the interface cannot be in promiscuous mode if
561 		 * there are no bpf listeners.  And if we are in promiscuous
562 		 * mode, we have to check if this packet is really ours.
563 		 *
564 		 * XXX This test does not support multicasts.
565 		 */
566 		if ((le->sc_if.if_flags & IFF_PROMISC)
567 		    && bcmp(et->ether_dhost, le->sc_addr,
568 			    sizeof(et->ether_dhost)) != 0
569 		    && bcmp(et->ether_dhost, etherbroadcastaddr,
570 			    sizeof(et->ether_dhost)) != 0)
571 			return;
572 	}
573 #endif
574 	/*
575 	 * Pull packet off interface.  Off is nonzero if packet
576 	 * has trailing header; leget will then force this header
577 	 * information to be at the front, but we still have to drop
578 	 * the type and length which are at the front of any trailer data.
579 	 */
580 	m = leget(buf, len, off, &le->sc_if);
581 	if (m == 0)
582 		return;
583 #ifdef RMP
584 	/*
585 	 * (XXX)
586 	 * This needs to be integrated with the ISO stuff in ether_input()
587 	 */
588 	if (et->ether_type == ETHERTYPE_IEEE) {
589 		/*
590 		 *  Snag the Logical Link Control header (IEEE 802.2).
591 		 */
592 		struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc);
593 
594 		/*
595 		 *  If the DSAP (and HP's extended DXSAP) indicate this
596 		 *  is an RMP packet, hand it to the raw input routine.
597 		 */
598 		if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) {
599 			static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT};
600 			static struct sockaddr rmp_src = {AF_RMP};
601 			static struct sockaddr rmp_dst = {AF_RMP};
602 
603 			bcopy(et->ether_shost, rmp_src.sa_data,
604 			      sizeof(et->ether_shost));
605 			bcopy(et->ether_dhost, rmp_dst.sa_data,
606 			      sizeof(et->ether_dhost));
607 
608 			raw_input(m, &rmp_sp, &rmp_src, &rmp_dst);
609 			return;
610 		}
611 	}
612 #endif
613 	ether_input(&le->sc_if, et, m);
614 }
615 
616 /*
617  * Routine to copy from mbuf chain to transmit
618  * buffer in board local memory.
619  */
620 leput(lebuf, m)
621 	register char *lebuf;
622 	register struct mbuf *m;
623 {
624 	register struct mbuf *mp;
625 	register int len, tlen = 0;
626 
627 	for (mp = m; mp; mp = mp->m_next) {
628 		len = mp->m_len;
629 		if (len == 0)
630 			continue;
631 		tlen += len;
632 		bcopy(mtod(mp, char *), lebuf, len);
633 		lebuf += len;
634 	}
635 	m_freem(m);
636 	if (tlen < LEMINSIZE) {
637 		bzero(lebuf, LEMINSIZE - tlen);
638 		tlen = LEMINSIZE;
639 	}
640 	return(tlen);
641 }
642 
643 /*
644  * Routine to copy from board local memory into mbufs.
645  */
646 struct mbuf *
647 leget(lebuf, totlen, off0, ifp)
648 	char *lebuf;
649 	int totlen, off0;
650 	struct ifnet *ifp;
651 {
652 	register struct mbuf *m;
653 	struct mbuf *top = 0, **mp = &top;
654 	register int off = off0, len;
655 	register char *cp;
656 	char *epkt;
657 
658 	lebuf += sizeof (struct ether_header);
659 	cp = lebuf;
660 	epkt = cp + totlen;
661 	if (off) {
662 		cp += off + 2 * sizeof(u_short);
663 		totlen -= 2 * sizeof(u_short);
664 	}
665 
666 	MGETHDR(m, M_DONTWAIT, MT_DATA);
667 	if (m == 0)
668 		return (0);
669 	m->m_pkthdr.rcvif = ifp;
670 	m->m_pkthdr.len = totlen;
671 	m->m_len = MHLEN;
672 
673 	while (totlen > 0) {
674 		if (top) {
675 			MGET(m, M_DONTWAIT, MT_DATA);
676 			if (m == 0) {
677 				m_freem(top);
678 				return (0);
679 			}
680 			m->m_len = MLEN;
681 		}
682 		len = min(totlen, epkt - cp);
683 		if (len >= MINCLSIZE) {
684 			MCLGET(m, M_DONTWAIT);
685 			if (m->m_flags & M_EXT)
686 				m->m_len = len = min(len, MCLBYTES);
687 			else
688 				len = m->m_len;
689 		} else {
690 			/*
691 			 * Place initial small packet/header at end of mbuf.
692 			 */
693 			if (len < m->m_len) {
694 				if (top == 0 && len + max_linkhdr <= m->m_len)
695 					m->m_data += max_linkhdr;
696 				m->m_len = len;
697 			} else
698 				len = m->m_len;
699 		}
700 		bcopy(cp, mtod(m, caddr_t), (unsigned)len);
701 		cp += len;
702 		*mp = m;
703 		mp = &m->m_next;
704 		totlen -= len;
705 		if (cp == epkt)
706 			cp = lebuf;
707 	}
708 	return (top);
709 }
710 
711 /*
712  * Process an ioctl request.
713  */
714 leioctl(ifp, cmd, data)
715 	register struct ifnet *ifp;
716 	int cmd;
717 	caddr_t data;
718 {
719 	register struct ifaddr *ifa = (struct ifaddr *)data;
720 	struct le_softc *le = (struct le_softc *) lecd.cd_devs[ifp->if_unit];
721 	struct lereg1 *ler1 = le->sc_r1;
722 	int s = splimp(), error = 0;
723 
724 	switch (cmd) {
725 
726 	case SIOCSIFADDR:
727 		ifp->if_flags |= IFF_UP;
728 		switch (ifa->ifa_addr->sa_family) {
729 #ifdef INET
730 		case AF_INET:
731 			leinit(ifp->if_unit);	/* before arpwhohas */
732 			((struct arpcom *)ifp)->ac_ipaddr =
733 				IA_SIN(ifa)->sin_addr;
734 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
735 			break;
736 #endif
737 #ifdef NS
738 		case AF_NS:
739 		    {
740 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
741 
742 			if (ns_nullhost(*ina))
743 				ina->x_host = *(union ns_host *)(le->sc_addr);
744 			else {
745 				/*
746 				 * The manual says we can't change the address
747 				 * while the receiver is armed,
748 				 * so reset everything
749 				 */
750 				ifp->if_flags &= ~IFF_RUNNING;
751 				bcopy((caddr_t)ina->x_host.c_host,
752 				    (caddr_t)le->sc_addr, sizeof(le->sc_addr));
753 			}
754 			leinit(ifp->if_unit); /* does le_setaddr() */
755 			break;
756 		    }
757 #endif
758 		default:
759 			leinit(ifp->if_unit);
760 			break;
761 		}
762 		break;
763 
764 	case SIOCSIFFLAGS:
765 		if ((ifp->if_flags & IFF_UP) == 0 &&
766 		    ifp->if_flags & IFF_RUNNING) {
767 			LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp);
768 			ifp->if_flags &= ~IFF_RUNNING;
769 		} else if (ifp->if_flags & IFF_UP &&
770 		    (ifp->if_flags & IFF_RUNNING) == 0)
771 			leinit(ifp->if_unit);
772 		/*
773 		 * If the state of the promiscuous bit changes, the interface
774 		 * must be reset to effect the change.
775 		 */
776 		if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) &&
777 		    (ifp->if_flags & IFF_RUNNING)) {
778 			le->sc_iflags = ifp->if_flags;
779 			lereset(ifp->if_unit);
780 			(void) lestart(ifp);
781 		}
782 		break;
783 
784 	default:
785 		error = EINVAL;
786 	}
787 	splx(s);
788 	return (error);
789 }
790 
791 leerror(unit, stat)
792 	int unit;
793 	int stat;
794 {
795 	struct le_softc *le = NULL;
796 
797 
798 	if (!ledebug)
799 		return;
800 
801 	le = (struct le_softc *) lecd.cd_devs[unit];
802 	/*
803 	 * Not all transceivers implement heartbeat
804 	 * so we only log CERR once.
805 	 */
806 	if ((stat & LE_CERR) && le->sc_cerr)
807 		return;
808 	log(LOG_WARNING,
809 	    "le%d: error: stat=%b\n", unit,
810 	    stat,
811 	    LE_STATUS_BITS);
812 }
813 
814 lererror(unit, msg)
815 	int unit;
816 	char *msg;
817 {
818 	register struct le_softc *le = lecd.cd_devs[unit];
819 	register struct lermd *rmd;
820 	int len;
821 
822 	if (!ledebug)
823 		return;
824 
825 	rmd = &le->sc_r2->ler2_rmd[le->sc_rmd];
826 	len = rmd->rmd3;
827 	log(LOG_WARNING,
828 	    "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1_bits=%b\n",
829 	    unit, msg,
830 	    len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown",
831 	    le->sc_rmd, len,
832 	    rmd->rmd1_bits,
833 	    "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3RBUF\2STP\1ENP");
834 }
835 
836 lexerror(unit)
837 	int unit;
838 {
839 	register struct le_softc *le = lecd.cd_devs[unit];
840 	register struct letmd *tmd;
841 	int len;
842 
843 	if (!ledebug)
844 		return;
845 
846 	tmd = le->sc_r2->ler2_tmd;
847 	len = -tmd->tmd2;
848 	log(LOG_WARNING,
849 	    "le%d: oerror: to %s: buf=%d, len=%d, tmd1_bits=%b, tmd3=%b\n",
850 	    unit,
851 	    len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown",
852 	    0, len,
853 	    tmd->tmd1_bits,
854 	    "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP",
855 	    tmd->tmd3,
856 	    "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
857 }
858