xref: /original-bsd/sys/vax/if/if_ec.c (revision 9a96b58b)
1 /*	if_ec.c	4.6	82/05/07	*/
2 
3 #include "ec.h"
4 #include "imp.h"
5 #include "loop.h"
6 
7 /*
8  * 3Com Ethernet Controller interface
9  */
10 
11 #include "../h/param.h"
12 #include "../h/systm.h"
13 #include "../h/mbuf.h"
14 #include "../h/pte.h"
15 #include "../h/buf.h"
16 #include "../h/protosw.h"
17 #include "../h/socket.h"
18 #include "../h/ubareg.h"
19 #include "../h/ubavar.h"
20 #include "../h/ecreg.h"
21 #include "../h/cpu.h"
22 #include "../h/mtpr.h"
23 #include "../h/vmmac.h"
24 #include "../net/in.h"
25 #include "../net/in_systm.h"
26 #include "../net/if.h"
27 #include "../net/if_ec.h"
28 #include "../net/if_uba.h"
29 #include "../net/ip.h"
30 #include "../net/ip_var.h"
31 #include "../net/pup.h"
32 #include "../net/route.h"
33 #include <errno.h>
34 
35 #define	ECMTU	1500
36 
37 int	ecprobe(), ecattach(), ecrint(), ecxint(), eccollide();
38 struct	uba_device *ecinfo[NEC];
39 u_short ecstd[] = { 0 };
40 struct	uba_driver ecdriver =
41 	{ ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo };
42 #define	ECUNIT(x)	minor(x)
43 
44 int	ecinit(),ecoutput(),ecreset();
45 struct mbuf *ecget();
46 
47 extern struct ifnet loif;
48 
49 /*
50  * Ethernet software status per interface.
51  *
52  * Each interface is referenced by a network interface structure,
53  * es_if, which the routing code uses to locate the interface.
54  * This structure contains the output queue for the interface, its address, ...
55  * We also have, for each interface, a UBA interface structure, which
56  * contains information about the UNIBUS resources held by the interface:
57  * map registers, buffered data paths, etc.  Information is cached in this
58  * structure for use by the if_uba.c routines in running the interface
59  * efficiently.
60  */
61 struct	ec_softc {
62 	struct	ifnet es_if;		/* network-visible interface */
63 	struct	ifuba es_ifuba;		/* UNIBUS resources */
64 	short	es_mask;		/* mask for current output delay */
65 #ifdef notdef
66 	short	es_delay;		/* current output delay */
67 	long	es_lastx;		/* host last transmitted to */
68 #endif
69 	short	es_oactive;		/* is output active? */
70 	caddr_t	es_buf[16];		/* virtual addresses of buffers */
71 	u_char	es_enaddr[6];		/* board's ethernet address */
72 } ec_softc[NEC];
73 
74 /*
75  * Do output DMA to determine interface presence and
76  * interrupt vector.  DMA is too short to disturb other hosts.
77  */
78 ecprobe(reg)
79 	caddr_t reg;
80 {
81 	register int br, cvec;		/* r11, r10 value-result */
82 	register struct ecdevice *addr = (struct ecdevice *)reg;
83 	register caddr_t ecbuf = (caddr_t) &umem[0][0600000];
84 
85 COUNT(ECPROBE);
86 #ifdef lint
87 	br = 0; cvec = br; br = cvec;
88 	ecrint(0); ecxint(0); eccollide(0);
89 #endif
90 	/*
91 	 * Make sure memory is turned on
92 	 */
93 	addr->ec_rcr = EC_AROM;
94 	/*
95 	 * Check for existence of buffers on Unibus.
96 	 * This won't work on a 780 until more work is done.
97 	 */
98 	if (badaddr((caddr_t) ecbuf, 2)) {
99 		printf("ec: buffer mem not found");
100 		return (0);
101 	}
102 
103 	/*
104 	 * Tell the system that the board has memory here, so it won't
105 	 * attempt to allocate the addresses later.
106 	 */
107 	ubamem(0, 0600000, 32*2);
108 
109 	/*
110 	 * Make a one byte packet in what should be buffer #0.
111 	 * Submit it for sending.  This whould cause an xmit interrupt.
112 	 * The xmit interrupt vector is 8 bytes after the receive vector,
113 	 * so adjust for this before returning.
114 	 */
115 	*(u_short *)ecbuf = (u_short) 03777;
116 	ecbuf[03777] = '\0';
117 	addr->ec_xcr = EC_XINTEN|EC_XWBN;
118 	DELAY(100000);
119 	addr->ec_xcr = EC_XCLR;
120 	if (cvec > 0 && cvec != 0x200)
121 		cvec -= 010;
122 		br += 2;
123 	return (1);
124 }
125 
126 /*
127  * Interface exists: make available by filling in network interface
128  * record.  System will initialize the interface when it is ready
129  * to accept packets.
130  */
131 ecattach(ui)
132 	struct uba_device *ui;
133 {
134 	register struct ec_softc *es = &ec_softc[ui->ui_unit];
135 	register struct sockaddr_in *sin;
136 	register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr;
137 	register int i, j;
138 	register u_char *cp;
139 COUNT(ECATTACH);
140 
141 	es->es_if.if_unit = ui->ui_unit;
142 	es->es_if.if_name = "ec";
143 	es->es_if.if_mtu = ECMTU;
144 	es->es_if.if_net = ui->ui_flags & 0xff;
145 
146 	/*
147 	 * Read the ethernet address off the board,
148 	 * one nibble at a time!
149 	 */
150 	addr->ec_xcr = EC_UECLR;
151 	addr->ec_rcr = EC_AROM;
152 	cp = es->es_enaddr;
153 	for (i=0; i<6; i++) {
154 		*cp = 0;
155 		for (j=0; j<=4; j+=4) {
156 			*cp |= ((addr->ec_rcr >> 8) & 0xf) << j;
157 			addr->ec_rcr = EC_AROM|EC_ASTEP;
158 			addr->ec_rcr = EC_AROM;
159 			addr->ec_rcr = EC_AROM|EC_ASTEP;
160 			addr->ec_rcr = EC_AROM;
161 			addr->ec_rcr = EC_AROM|EC_ASTEP;
162 			addr->ec_rcr = EC_AROM;
163 			addr->ec_rcr = EC_AROM|EC_ASTEP;
164 			addr->ec_rcr = EC_AROM;
165 		}
166 		cp++;
167 	}
168 	printf("ec%d: addr=%x:%x:%x:%x:%x:%x\n", ui->ui_unit,
169 		es->es_enaddr[0]&0xff, es->es_enaddr[1]&0xff,
170 		es->es_enaddr[2]&0xff, es->es_enaddr[3]&0xff,
171 		es->es_enaddr[4]&0xff, es->es_enaddr[5]&0xff);
172 	es->es_if.if_host[0] = ((es->es_enaddr[3]&0xff)<<16) |
173 	    ((es->es_enaddr[4]&0xff)<<8) | (es->es_enaddr[5]&0xff);
174 	sin = (struct sockaddr_in *)&es->es_if.if_addr;
175 	sin->sin_family = AF_INET;
176 	sin->sin_addr = if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]);
177 
178 	sin = (struct sockaddr_in *)&es->es_if.if_broadaddr;
179 	sin->sin_family = AF_INET;
180 	sin->sin_addr = if_makeaddr(es->es_if.if_net, 0);
181 	es->es_if.if_flags = IFF_BROADCAST;
182 
183 	es->es_if.if_init = ecinit;
184 	es->es_if.if_output = ecoutput;
185 	es->es_if.if_ubareset = ecreset;
186 	for (i=0; i<16; i++)
187 		es->es_buf[i] = &umem[ui->ui_ubanum][0600000+2048*i];
188 	if_attach(&es->es_if);
189 #if NIMP == 0
190 	/* here's one for you john baby.... */
191 	if (ui->ui_flags &~ 0xff)
192 		eclhinit((ui->ui_flags &~ 0xff) | 0x0a);
193 #endif
194 }
195 
196 /*
197  * Reset of interface after UNIBUS reset.
198  * If interface is on specified uba, reset its state.
199  */
200 ecreset(unit, uban)
201 	int unit, uban;
202 {
203 	register struct uba_device *ui;
204 COUNT(ECRESET);
205 
206 	if (unit >= NEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 ||
207 	    ui->ui_ubanum != uban)
208 		return;
209 	printf(" ec%d", unit);
210 	ecinit(unit);
211 }
212 
213 /*
214  * Initialization of interface; clear recorded pending
215  * operations, and reinitialize UNIBUS usage.
216  */
217 ecinit(unit)
218 	int unit;
219 {
220 	register struct ec_softc *es = &ec_softc[unit];
221 	register struct uba_device *ui = ecinfo[unit];
222 	register struct ecdevice *addr;
223 	register i;
224 	int s;
225 
226 #ifdef notdef
227 	if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
228 	    sizeof (struct ec_header), (int)btoc(ECMTU)) == 0) {
229 		printf("ec%d: can't initialize\n", unit);
230 		es->es_if.if_flags &= ~IFF_UP;
231 		return;
232 	}
233 #endif
234 	addr = (struct ecdevice *)ui->ui_addr;
235 
236 	/*
237 	 * Hang receive buffers and start any pending
238 	 * writes by faking a transmit complete.
239 	 * Writing into the rcr also makes sure the memory
240 	 * is turned on.
241 	 */
242 	s = splimp();
243 	for (i=ECRHBF; i>=ECRLBF; i--)
244 		addr->ec_rcr = EC_READ|i;
245 	es->es_oactive = 1;
246 	es->es_if.if_flags |= IFF_UP;
247 	ecxint(unit);
248 	splx(s);
249 	if_rtinit(&es->es_if, RTF_DIRECT|RTF_UP);
250 }
251 
252 #ifdef notdef
253 int	enalldelay = 0;
254 int	eclastdel = 25;
255 int	enlastmask = (~0) << 5;
256 #endif
257 
258 /*
259  * Start or restart output on interface.
260  * If interface is already active, then this is a retransmit
261  * after a collision, and just restuff registers.
262  * If interface is not already active, get another datagram
263  * to send off of the interface queue, and map it to the interface
264  * before starting the output.
265  */
266 ecstart(dev)
267 	dev_t dev;
268 {
269         int unit = ECUNIT(dev);
270 	struct uba_device *ui = ecinfo[unit];
271 	register struct ec_softc *es = &ec_softc[unit];
272 	register struct ecdevice *addr;
273 	struct mbuf *m;
274 	caddr_t ecbuf;
275 	int dest;
276 COUNT(ECSTART);
277 
278 	if (es->es_oactive)
279 		goto restart;
280 
281 	/*
282 	 * Not already active: dequeue another request
283 	 * and copy it into the buffer.  If no more requests,
284 	 * just return.
285 	 */
286 	IF_DEQUEUE(&es->es_if.if_snd, m);
287 	if (m == 0) {
288 		es->es_oactive = 0;
289 		return;
290 	}
291 #ifdef notdef
292 	dest = mtod(m, struct ec_header *)->ec_dhost; /* wrong! */
293 #endif
294 	ecput(es->es_buf[ECTBF], m);
295 
296 #ifdef notdef
297 	/*
298 	 * Ethernet cannot take back-to-back packets (no
299 	 * buffering in interface).  To avoid overrunning
300 	 * receivers, enforce a small delay (about 1ms) in interface:
301 	 *	* between all packets when ecalldelay
302 	 *	* whenever last packet was broadcast
303 	 *	* whenever this packet is to same host as last packet
304 	 */
305 	if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
306 		es->es_delay = eclastdel;
307 		es->es_mask = eclastmask;
308 	}
309 	es->es_lastx = dest;
310 #endif
311 
312 restart:
313 	/*
314 	 * Start the output.
315 	 */
316 	addr = (struct ecdevice *)ui->ui_addr;
317 	addr->ec_xcr = EC_WRITE|ECTBF;
318 	es->es_oactive = 1;
319 }
320 
321 /*
322  * Ethernet interface transmitter interrupt.
323  * Start another output if more data to send.
324  */
325 ecxint(unit)
326 	int unit;
327 {
328 	register struct uba_device *ui = ecinfo[unit];
329 	register struct ec_softc *es = &ec_softc[unit];
330 	register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr;
331 COUNT(ECXINT);
332 
333 	if (es->es_oactive == 0)
334 		return;
335 	if (addr->ec_xcr&EC_XDONE == 0 || addr->ec_xcr&EC_XBN != ECTBF)
336 		printf("ec%d: strange xmit interrupt!\n", unit);
337 	es->es_if.if_opackets++;
338 	es->es_oactive = 0;
339 	es->es_mask = ~0;
340 	addr->ec_xcr = EC_XCLR;
341 	/*
342 	 * There shouldn't ever be any mbuf's to free, but just in case...
343 	 */
344 	if (es->es_ifuba.ifu_xtofree) {
345 		m_freem(es->es_ifuba.ifu_xtofree);
346 		es->es_ifuba.ifu_xtofree = 0;
347 	}
348 	if (es->es_if.if_snd.ifq_head == 0) {
349 #ifdef notdef
350 		es->es_lastx = 0; /* ? */
351 #endif
352 		return;
353 	}
354 	ecstart(unit);
355 }
356 
357 /*
358  * Collision on ethernet interface.  Do exponential
359  * backoff, and retransmit.  If have backed off all
360  * the way print warning diagnostic, and drop packet.
361  */
362 eccollide(unit)
363 	int unit;
364 {
365 	struct ec_softc *es = &ec_softc[unit];
366 COUNT(ECCOLLIDE);
367 
368 	printf("ec%d: collision\n", unit);
369 	es->es_if.if_collisions++;
370 	if (es->es_oactive == 0)
371 		return;
372 	ecdocoll(unit);
373 }
374 
375 ecdocoll(unit)
376 	int unit;
377 {
378 	register struct ec_softc *es = &ec_softc[unit];
379 	register struct ecdevice *addr =
380 	    (struct ecdevice *)ecinfo[unit]->ui_addr;
381 	register i;
382 	int delay;
383 
384 	/*
385 	 * Es_mask is a 16 bit number with n low zero bits, with
386 	 * n the number of backoffs.  When es_mask is 0 we have
387 	 * backed off 16 times, and give up.
388 	 */
389 	if (es->es_mask == 0) {
390 		es->es_if.if_oerrors++;
391 		printf("ec%d: send error\n", unit);
392 		/*
393 		 * Reset interface, then requeue rcv buffers.
394 		 * Some incoming packets may be lost, but that
395 		 * can't be helped.
396 		 */
397 		addr->ec_xcr = EC_UECLR;
398 		for (i=ECRHBF; i>=ECRLBF; i--)
399 			addr->ec_rcr = EC_READ|i;
400 		/*
401 		 * Reset and transmit next packet (if any).
402 		 */
403 		es->es_oactive = 0;
404 		es->es_mask = ~0;
405 		if (es->es_if.if_snd.ifq_head)
406 			ecstart(unit);
407 		return;
408 	}
409 	/*
410 	 * Do exponential backoff.  Compute delay based on low bits
411 	 * of the interval timer.  Then delay for that number of
412 	 * slot times.  A slot time is 51.2 microseconds (rounded to 51).
413 	 * This does not take into account the time already used to
414 	 * process the interrupt.
415 	 */
416 	es->es_mask <<= 1;
417 	delay = mfpr(ICR) &~ es->es_mask;
418 	DELAY(delay * 51);
419 	/*
420 	 * Clear the controller's collision flag, thus enabling retransmit.
421 	 */
422 	addr->ec_xcr = EC_JCLR;
423 }
424 
425 #ifdef notdef
426 struct	sockaddr_pup pupsrc = { AF_PUP };
427 struct	sockaddr_pup pupdst = { AF_PUP };
428 struct	sockproto pupproto = { PF_PUP };
429 #endif
430 /*
431  * Ethernet interface receiver interrupt.
432  * If input error just drop packet.
433  * Otherwise purge input buffered data path and examine
434  * packet to determine type.  If can't determine length
435  * from type, then have to drop packet.  Othewise decapsulate
436  * packet based on type and pass to type specific higher-level
437  * input routine.
438  */
439 ecrint(unit)
440 	int unit;
441 {
442 	struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
443 COUNT(ECRINT);
444 
445 #ifdef notdef
446 	printf("ec%d: ecrint:%d\n", unit, addr->ec_rcr & 0xf);
447 #endif
448 	while (addr->ec_rcr & EC_RDONE)
449 		ecread(unit);
450 }
451 
452 ecread(unit)
453 	int unit;
454 {
455 	register struct ec_softc *es = &ec_softc[unit];
456 	struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
457 	register struct ec_header *ec;
458     	struct mbuf *m;
459 	int len, off, resid;
460 	register struct ifqueue *inq;
461 	caddr_t ecbuf;
462 	int ecoff;
463 	int buf;
464 COUNT(ECREAD);
465 
466 	es->es_if.if_ipackets++;
467 	buf = addr->ec_rcr & EC_RBN;
468 	if (buf < ECRLBF || buf > ECRHBF)
469 		panic("ecrint");
470 	ecbuf = es->es_buf[buf];
471 	ecoff = *(short *)ecbuf;
472 	if (ecoff <= ECRDOFF || ecoff > 2046) {
473 		es->es_if.if_ierrors++;
474 #ifdef notdef
475 		if (es->es_if.if_ierrors % 100 == 0)
476 			printf("ec%d: += 100 input errors\n", unit);
477 #endif
478 		printf("ec%d: input error (offset=%d)\n", unit, ecoff);
479 		goto setup;
480 	}
481 
482 	/*
483 	 * Get input data length.
484 	 * Get pointer to ethernet header (in input buffer).
485 	 * Deal with trailer protocol: if type is PUP trailer
486 	 * get true type from first 16-bit word past data.
487 	 * Remember that type was trailer by setting off.
488 	 */
489 	len = ecoff - ECRDOFF - sizeof (struct ec_header);
490 	ec = (struct ec_header *)(ecbuf + ECRDOFF);
491 #define	ecdataaddr(ec, off, type)	((type)(((caddr_t)((ec)+1)+(off))))
492 	if (ec->ec_type >= ECPUP_TRAIL &&
493 	    ec->ec_type < ECPUP_TRAIL+ECPUP_NTRAILER) {
494 		off = (ec->ec_type - ECPUP_TRAIL) * 512;
495 		if (off >= ECMTU)
496 			goto setup;		/* sanity */
497 		ec->ec_type = *ecdataaddr(ec, off, u_short *);
498 		resid = *(ecdataaddr(ec, off+2, u_short *));
499 		if (off + resid > len)
500 			goto setup;		/* sanity */
501 		len = off + resid;
502 	} else
503 		off = 0;
504 	if (len == 0)
505 		goto setup;
506 
507 	/*
508 	 * Pull packet off interface.  Off is nonzero if packet
509 	 * has trailing header; ecget will then force this header
510 	 * information to be at the front, but we still have to drop
511 	 * the type and length which are at the front of any trailer data.
512 	 */
513 	m = ecget(ecbuf, len, off);
514 	if (m == 0)
515 		goto setup;
516 	if (off) {
517 		m->m_off += 2 * sizeof (u_short);
518 		m->m_len -= 2 * sizeof (u_short);
519 	}
520 	switch (ec->ec_type) {
521 
522 #ifdef INET
523 	case ECPUP_IPTYPE:
524 		schednetisr(NETISR_IP);
525 		inq = &ipintrq;
526 		break;
527 #endif
528 #ifdef notdef
529 #ifdef PUP
530 	case ECPUP_PUPTYPE: {
531 		struct pup_header *pup = mtod(m, struct pup_header *);
532 
533 		pupproto.sp_protocol = pup->pup_type;
534 		pupdst.spup_addr = pup->pup_dport;
535 		pupsrc.spup_addr = pup->pup_sport;
536 		raw_input(m, &pupproto, (struct sockaddr *)&pupsrc,
537 		  (struct sockaddr *)&pupdst);
538 		goto setup;
539 	}
540 #endif
541 #endif
542 	default:
543 		m_freem(m);
544 		goto setup;
545 	}
546 
547 	if (IF_QFULL(inq)) {
548 		IF_DROP(inq);
549 		m_freem(m);
550 	} else
551 		IF_ENQUEUE(inq, m);
552 
553 setup:
554 	/*
555 	 * Reset for next packet.
556 	 */
557 	addr->ec_rcr = EC_READ|EC_RCLR|buf;
558 }
559 
560 /*
561  * Ethernet output routine.
562  * Encapsulate a packet of type family for the local net.
563  * Use trailer local net encapsulation if enough data in first
564  * packet leaves a multiple of 512 bytes of data in remainder.
565  * If destination is this address or broadcast, send packet to
566  * loop device to kludge around the fact that 3com interfaces can't
567  * talk to themselves.
568  */
569 ecoutput(ifp, m0, dst)
570 	struct ifnet *ifp;
571 	struct mbuf *m0;
572 	struct sockaddr *dst;
573 {
574 	int type, dest, s, error;
575 	register struct ec_softc *es = &ec_softc[ifp->if_unit];
576 	register struct mbuf *m = m0;
577 	register struct ec_header *ec;
578 	register int off;
579 	register int i;
580 	struct mbuf *mcopy = (struct mbuf *) 0;		/* Null */
581 
582 COUNT(ECOUTPUT);
583 	switch (dst->sa_family) {
584 
585 #ifdef INET
586 	case AF_INET:
587 		dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
588 		if ((dest &~ 0xff) == 0)
589 			mcopy = m_copy(m, 0, M_COPYALL);
590 		else if (dest == ((struct sockaddr_in *)&es->es_if.if_addr)->
591 		    sin_addr.s_addr) {
592 			mcopy = m;
593 			goto gotlocal;
594 		}
595 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
596 		if (off > 0 && (off & 0x1ff) == 0 &&
597 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
598 			type = ECPUP_TRAIL + (off>>9);
599 			m->m_off -= 2 * sizeof (u_short);
600 			m->m_len += 2 * sizeof (u_short);
601 			*mtod(m, u_short *) = ECPUP_IPTYPE;
602 			*(mtod(m, u_short *) + 1) = m->m_len;
603 			goto gottrailertype;
604 		}
605 		type = ECPUP_IPTYPE;
606 		off = 0;
607 		goto gottype;
608 #endif
609 #ifdef notdef
610 #ifdef PUP
611 	case AF_PUP:
612 		dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host;
613 		type = ECPUP_PUPTYPE;
614 		off = 0;
615 		goto gottype;
616 #endif
617 #endif
618 
619 	default:
620 		printf("ec%d: can't handle af%d\n", ifp->if_unit,
621 			dst->sa_family);
622 		error = EAFNOSUPPORT;
623 		goto bad;
624 	}
625 
626 gottrailertype:
627 	/*
628 	 * Packet to be sent as trailer: move first packet
629 	 * (control information) to end of chain.
630 	 */
631 	while (m->m_next)
632 		m = m->m_next;
633 	m->m_next = m0;
634 	m = m0->m_next;
635 	m0->m_next = 0;
636 	m0 = m;
637 
638 gottype:
639 	/*
640 	 * Add local net header.  If no space in first mbuf,
641 	 * allocate another.
642 	 */
643 	if (m->m_off > MMAXOFF ||
644 	    MMINOFF + sizeof (struct ec_header) > m->m_off) {
645 		m = m_get(M_DONTWAIT);
646 		if (m == 0) {
647 			error = ENOBUFS;
648 			goto bad;
649 		}
650 		m->m_next = m0;
651 		m->m_off = MMINOFF;
652 		m->m_len = sizeof (struct ec_header);
653 	} else {
654 		m->m_off -= sizeof (struct ec_header);
655 		m->m_len += sizeof (struct ec_header);
656 	}
657 	ec = mtod(m, struct ec_header *);
658 	for (i=0; i<6; i++)
659 		ec->ec_shost[i] = es->es_enaddr[i];
660 	if ((dest &~ 0xff) == 0)
661 		for (i=0; i<6; i++)
662 			ec->ec_dhost[i] = 0xff;
663 	else {
664 		ec->ec_dhost[0] = es->es_enaddr[0];
665 		ec->ec_dhost[1] = es->es_enaddr[1];
666 		ec->ec_dhost[2] = es->es_enaddr[2];
667 		ec->ec_dhost[3] = (dest>>8) & 0xff;
668 		ec->ec_dhost[4] = (dest>>16) & 0xff;
669 		ec->ec_dhost[5] = (dest>>24) & 0xff;
670 	}
671 	ec->ec_type = type;
672 
673 	/*
674 	 * Queue message on interface, and start output if interface
675 	 * not yet active.
676 	 */
677 	s = splimp();
678 	if (IF_QFULL(&ifp->if_snd)) {
679 		IF_DROP(&ifp->if_snd);
680 		error = ENOBUFS;
681 		goto qfull;
682 	}
683 	IF_ENQUEUE(&ifp->if_snd, m);
684 	if (es->es_oactive == 0)
685 		ecstart(ifp->if_unit);
686 	splx(s);
687 gotlocal:
688 	if (mcopy)				/* Kludge, but it works! */
689 		return(looutput(&loif, mcopy, dst));
690 	else
691 		return (0);
692 qfull:
693 	m0 = m;
694 	splx(s);
695 bad:
696 	m_freem(m0);
697 	return(error);
698 }
699 
700 /*
701  * Routine to copy from mbufs to UNIBUS memory.
702  * Similar in spirit to if_wubaput.
703  */
704 ecput(ecbuf, m)
705 	char *ecbuf;
706 	struct mbuf *m;
707 {
708 	register int len;
709 	register struct mbuf *mp;
710 	register char *bp, *mcp;
711 	register int i;
712 
713 COUNT(ECPUT);
714 	len = 0;
715 	for (mp=m; mp; mp=mp->m_next)
716 		len += mp->m_len;
717 	*(u_short *)ecbuf = 2048 - len;
718 	bp = ecbuf + 2048 - len;
719 	mp = m;
720 	while (mp) {
721 		mcp = mtod(mp, char *);
722 		for (i=0; i<mp->m_len; i++)
723 			*bp++ = *mcp++;
724 		mp = m_free(mp);
725 	}
726 	if (bp != ecbuf+2048)
727 		printf("ec: bad ecput!\n");
728 }
729 
730 /*
731  * Routine to copy from UNIBUS memory into mbufs.
732  * Similar in spirit to if_rubaget.
733  */
734 struct mbuf *
735 ecget(ecbuf, totlen, off0)
736 	char *ecbuf;
737 	int totlen, off0;
738 {
739 	struct mbuf *top, **mp, *m;
740 	int off = off0;
741 	int len;
742 	register char *cp = ecbuf + ECRDOFF + sizeof (struct ec_header);
743 	register char *mcp;
744 	register int i;
745 
746 COUNT(ECGET);
747 	top = 0;
748 	mp = &top;
749 	while (totlen > 0) {
750 		MGET(m, 0);
751 		if (m == 0)
752 			goto bad;
753 		if (off) {
754 			len = totlen - off;
755 			cp = ecbuf + ECRDOFF + sizeof (struct ec_header) + off;
756 		} else
757 			len = totlen;
758 		if (len >= CLBYTES) {
759 			struct mbuf *p;
760 
761 			MCLGET(p, 1);
762 			if (p != 0) {
763 				m->m_len = len = CLBYTES;
764 				m->m_off = (int)p - (int)m;
765 			} else {
766 				m->m_len = len = MIN(MLEN, len);
767 				m->m_off = MMINOFF;
768 			}
769 		} else {
770 			m->m_len = len = MIN(MLEN, len);
771 			m->m_off = MMINOFF;
772 		}
773 		mcp = mtod(m, char *);
774 		for (i=0; i<len; i++)
775 			*mcp++ = *cp++;
776 		*mp = m;
777 		mp = &m->m_next;
778 		if (off) {
779 			off += len;
780 			if (off == totlen) {
781 				cp = ecbuf + ECRDOFF +
782 				    sizeof (struct ec_header);
783 				off = 0;
784 				totlen = off0;
785 			}
786 		} else
787 			totlen -= len;
788 	}
789 	return (top);
790 bad:
791 	m_freem(top);
792 	return (0);
793 }
794 
795 #if NIMP == 0 && NEC > 0
796 /*
797  * Logical host interface driver.
798  * Allows host to appear as an ARPAnet
799  * logical host.  Must also have routing
800  * table entry set up to forward packets
801  * to appropriate gateway on localnet.
802  */
803 
804 struct	ifnet eclhif;
805 int	eclhoutput();
806 
807 /*
808  * Called by localnet interface to allow logical
809  * host interface to "attach".  Nothing should ever
810  * be sent locally to this interface, it's purpose
811  * is simply to establish the host's arpanet address.
812  */
813 eclhinit(addr)
814 	int addr;
815 {
816 	register struct ifnet *ifp = &eclhif;
817 	register struct sockaddr_in *sin;
818 
819 COUNT(ECLHINIT);
820 	ifp->if_name = "lh";
821 	ifp->if_mtu = ECMTU;
822 	sin = (struct sockaddr_in *)&ifp->if_addr;
823 	sin->sin_family = AF_INET;
824 	sin->sin_addr.s_addr = addr;
825 	ifp->if_net = sin->sin_addr.s_net;
826 	ifp->if_flags = IFF_UP;
827 	ifp->if_output = eclhoutput;	/* should never be used */
828 	if_attach(ifp);
829 }
830 
831 eclhoutput(ifp, m0, dst)
832 	struct ifnet *ifp;
833 	struct mbuf *m0;
834 	struct sockaddr *dst;
835 {
836 COUNT(ECLHOUTPUT);
837 	ifp->if_oerrors++;
838 	m_freem(m0);
839 	return (0);
840 }
841 #endif
842