xref: /original-bsd/sys/news3400/if/if_en.c (revision 68d9582f)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
7  *
8  * %sccs.include.redist.c%
9  *
10  * from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY
11  *
12  *	@(#)if_en.c	7.1 (Berkeley) 06/04/92
13  */
14 
15 #include "en.h"
16 #include "rawether.h"
17 #include "bpfilter.h"
18 
19 #if NEN > 0
20 
21 /*
22  * Interlan Ethernet Communications Controller interface
23  */
24 #include "types.h"
25 #include "../include/fix_machine_type.h"
26 #include "../include/pte.h"
27 
28 #include "param.h"
29 #include "systm.h"
30 #include "mbuf.h"
31 #include "buf.h"
32 #include "protosw.h"
33 #include "socket.h"
34 #include "ioctl.h"
35 #include "errno.h"
36 #include "time.h"
37 #include "cdefs.h"
38 
39 #include "net/if.h"
40 #include "net/netisr.h"
41 #include "net/route.h"
42 
43 #ifdef INET
44 #include "netinet/in.h"
45 #include "netinet/in_systm.h"
46 #include "netinet/in_var.h"
47 #include "netinet/ip.h"
48 #include "netinet/if_ether.h"
49 #endif
50 
51 #include "../if/if_news.h"
52 #include "../if/if_en.h"
53 
54 #ifdef CPU_SINGLE
55 #include "../hbdev/hbvar.h"
56 #define	iop_device	hb_device
57 #define	iop_driver	hb_driver
58 #define	ii_unit		hi_unit
59 #define	ii_intr		hi_intr
60 #define	ii_alive	hi_alive
61 #else
62 #include "../iop/iopvar.h"
63 #endif
64 
65 int	enprobe(), enattach(), enrint(), enxint();
66 struct	mbuf *m_devget();
67 
68 #ifdef CPU_SINGLE
69 struct	hb_device *eninfo[NEN];
70 struct	hb_driver endriver = { enprobe, 0, enattach, 0, 0, "en", eninfo };
71 #else
72 struct	iop_device *eninfo[NEN];
73 struct	iop_driver endriver = { enprobe, 0, enattach, 0, "en", eninfo };
74 #endif
75 
76 #define	ENUNIT(x)	minor(x)
77 
78 int	eninit(),enoutput(),enioctl(),enreset(),enwatch(),enstart();
79 int	endebug = 0;
80 
81 struct ether_addr {
82 	u_char	addr[6];
83 };
84 
85 extern struct ifnet loif;
86 
87 struct en_softc en_softc[NEN];
88 struct ether_addr myether[NEN];
89 
90 #if NBPFILTER > 0
91 #include "../net/bpf.h"
92 caddr_t	en_bpf[NEN];
93 #endif
94 
95 enprobe(ii)
96 	struct iop_device *ii;
97 {
98 
99 	return (en_probe(ii));
100 }
101 
102 /*
103  * Interface exists: make available by filling in network interface
104  * record.  System will initialize the interface when it is ready
105  * to accept packets.  A STATUS command is done to get the ethernet
106  * address and other interesting data.
107  */
108 enattach(ii)
109 	register struct iop_device *ii;
110 {
111 	register struct en_softc *es = &en_softc[ii->ii_unit];
112 	register struct ifnet *ifp = &es->es_if;
113 	extern char *ether_sprintf();
114 
115 	en_attach(ii->ii_unit);
116 	bcopy((caddr_t)es->es_addr, &myether[ii->ii_unit],
117 		sizeof(struct ether_addr));
118 	printf("en%d: hardware address %s\n",
119 		ii->ii_unit, ether_sprintf((u_char *)es->es_addr));
120 	ifp->if_unit = ii->ii_unit;
121 	ifp->if_name = "en";
122 	ifp->if_mtu = ETHERMTU;
123 	ifp->if_init = eninit;
124 	ifp->if_ioctl = enioctl;
125 	ifp->if_output = ether_output;
126 #ifdef NOTDEF /* KU:XXX if_reset is obsolete */
127 	ifp->if_reset = enreset;
128 #endif
129 	ifp->if_start = enstart;
130 	ifp->if_flags = IFF_BROADCAST;
131 #if NBPFILTER > 0
132 	{
133 		static struct bpf_devp dev =
134 			{ DLT_EN10MB, sizeof(struct ether_header) };
135 
136 		bpfattach(&en_bpf[ii->ii_unit], ifp, &dev);
137 	}
138 #endif
139 	if_attach(ifp);
140 }
141 
142 /*
143  * Reset of interface after IOP reset.
144  */
145 enreset(unit)
146 	int unit;
147 {
148 	register struct iop_device *ii;
149 
150 	if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0)
151 		return;
152 	printf(" en%d", unit);
153 	en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
154 	en_softc[unit].es_flags &= ~ENF_RUNNING;
155 	eninit(unit);
156 }
157 
158 /*
159  * Initialization of interface; clear recorded pending
160  * operations, and reinitialize IOP usage.
161  */
162 eninit(unit)
163 	int unit;
164 {
165 	register struct en_softc *es = &en_softc[unit];
166 	register struct ifnet *ifp = &es->es_if;
167 	int s;
168 
169 	/* not yet, if address still unknown */
170 	if (ifp->if_addrlist == (struct ifaddr *)0)
171 		return;
172 	if (es->es_flags & ENF_RUNNING)
173 		return;
174 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
175 		if (if_newsinit(&es->es_ifnews,
176 		    sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) {
177 			printf("en%d: can't initialize\n", unit);
178 			es->es_if.if_flags &= ~IFF_UP;
179 			return;
180 		}
181 		ifp->if_watchdog = enwatch;
182 		es->es_interval = ENWATCHINTERVAL;
183 		ifp->if_timer = es->es_interval;
184 		s = splimp();
185 		en_init(unit);
186 		splx(s);
187 	}
188 	es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS;
189 	es->es_flags |= ENF_RUNNING;
190 }
191 
192 /*
193  * Start output on interface.
194  * Get another datagram to send off of the interface queue,
195  * and map it to the interface before starting the output.
196  */
197 enstart(ifp)
198 	register struct ifnet *ifp;
199 {
200         int unit = ifp->if_unit, len;
201 	register struct en_softc *es = &en_softc[unit];
202 	register struct mbuf *m;
203 
204 	IF_DEQUEUE(&es->es_if.if_snd, m);
205 	if (m == 0)
206 		return(0);
207 #ifdef CPU_SINGLE
208 	es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit);
209 #endif
210 	len = if_wnewsput(&es->es_ifnews, m);
211 	/*
212 	 * Ensure minimum packet length.
213 	 * This makes the safe assumtion that there are no virtual holes
214 	 * after the data.
215 	 * For security, it might be wise to zero out the added bytes,
216 	 * but we're mainly interested in speed at the moment.
217 	 */
218 	if (len - sizeof(struct ether_header) < ETHERMIN)
219 		len = ETHERMIN + sizeof(struct ether_header);
220 	en_start(unit, len);
221 #if NBPFILTER > 0
222 	/*
223 	 * If bpf is listening on this interface, let it
224 	 * see the packet before we commit it to the wire.
225 	 */
226 	if (en_bpf[unit]) {
227 #ifdef CPU_SINGLE
228 		bpf_tap(en_bpf[unit], es->es_ifnews.ifn_waddr, len);
229 #else
230 		bpf_mtap(en_bpf[unit], m);
231 #endif
232 	}
233 #endif /* NBPFILTER > 0 */
234 	es->es_if.if_flags |= IFF_OACTIVE;
235 	return(0);
236 }
237 
238 /*
239  * Transmit done interrupt.
240  */
241 _enxint(unit, error, collision)
242 	int unit;
243 	int error, collision;
244 {
245 	register struct en_softc *es = &en_softc[unit];
246 
247 #ifdef notyet /* KU:XXX */
248 	intrcnt[INTR_ETHER0 + unit]++;
249 #endif
250 	if ((es->es_if.if_flags & IFF_OACTIVE) == 0) {
251 		printf("en%d: stray xmit interrupt\n", unit);
252 /*
253 		return;
254 */
255 	} else {
256 		es->es_if.if_flags &= ~IFF_OACTIVE;
257 		es->es_if.if_opackets++;
258 	}
259 	if (error)
260 		es->es_if.if_oerrors++;
261 	if (collision)
262 		es->es_if.if_collisions++;
263 	enstart(&es->es_if);
264 }
265 
266 /*
267  * Ethernet interface receiver interrupt.
268  * If input error just drop packet.
269  * Otherwise purge input buffered data path and examine
270  * packet to determine type.  If can't determine length
271  * from type, then have to drop packet.  Othewise decapsulate
272  * packet based on type and pass to type specific higher-level
273  * input routine.
274  */
275 _enrint(unit, len)
276 	int unit;
277 	register int len;
278 {
279 	register struct en_softc *es = &en_softc[unit];
280 	register struct en_rheader *en;
281     	struct mbuf *m;
282 	int off, resid, s;
283 	int	type;
284 	register struct ensw *esp;
285 	extern struct mbuf *if_rnewsget();
286 
287 #ifdef notyet /* KU:XXX */
288 	intrcnt[INTR_ETHER0 + unit]++;
289 #endif
290 	es->es_if.if_ipackets++;
291 	if ((es->es_flags & ENF_RUNNING) == 0)
292 		return;
293 	en = (struct en_rheader *)(es->es_ifnews.ifn_raddr);
294 	if (len < ETHERMIN || len > ETHERMTU) {
295 		es->es_if.if_ierrors++;
296 		return;
297 	}
298 #if NBPFILTER > 0
299 #if NRAWETHER > 0
300 	etherinput(unit, en, len + sizeof(struct en_rheader));
301 #endif
302 	/*
303 	 * Check if there's a bpf filter listening on this interface.
304 	 * If so, hand off the raw packet to enet.
305 	 */
306 	if (en_bpf[unit]) {
307 		bpf_tap(en_bpf[unit], es->es_ifnews.ifn_raddr,
308 			len + sizeof(struct en_rheader));
309 		/*
310 		 * Note that the interface cannot be in promiscuous mode if
311 		 * there are no bpf listeners.	And if we are in promiscuous
312 		 * mode, we have to check if this packet is really ours.
313 		 *
314 		 * XXX This test does not support multicasts.
315 		 */
316 		 if ((es->es_if.if_flags & IFF_PROMISC)
317 		     && bcmp(en->enr_dhost, es->es_addr,
318 				sizeof(en->enr_dhost)) != 0
319 		     && bcmp(en->enr_dhost, etherbroadcastaddr,
320 				sizeof(en->enr_dhost)) != 0)
321 			return;
322 	}
323 #else /* NBPFILTER > 0 */
324 #if NRAWETHER > 0
325 	if (etherinput(unit, en, len + sizeof(struct en_rheader)))
326 		return;
327 #endif
328 #endif /* NBPFILTER > 0 */
329 	/*
330 	 * Deal with trailer protocol: if type is trailer type
331 	 * get true type from first 16-bit word past data.
332 	 * Remember that type was trailer by setting off.
333 	 */
334 	en->enr_type = ntohs((u_short)en->enr_type);
335 #define	endataaddr(en, off, type)	((type)(((caddr_t)((en)+1)+(off))))
336 	if (en->enr_type >= ETHERTYPE_TRAIL &&
337 	    en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
338 		off = (en->enr_type - ETHERTYPE_TRAIL) * 512;
339 		if (off >= ETHERMTU)
340 			return;
341 		en->enr_type = ntohs(*endataaddr(en, off, u_short *));
342 		resid = ntohs(*(endataaddr(en, off+2, u_short *)));
343 		if (off + resid > len)
344 			return;
345 		len = off + resid;
346 	} else
347 		off = 0;
348 	/*
349 	 * Pull packet off interface.  Off is nonzero if packet
350 	 * has trailing header; m_devget will then force this header
351 	 * information to be at the front, but we still have to drop
352 	 * the type and length which are at the front of any trailer data.
353 	 * KU:XXX really?
354 	 */
355 	type = en->enr_type;
356 	m = m_devget((char *)(en + 1), len, off, &es->es_if, 0);
357 	if (m == 0)
358 		return;
359 	ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m);
360 }
361 
362 /*
363  * Watchdog routine, request statistics from board.
364  */
365 enwatch(unit)
366 	int unit;
367 {
368 	register struct en_softc *es = &en_softc[unit];
369 	register struct ifnet *ifp = &es->es_if;
370 
371 	ifp->if_timer = es->es_interval;
372 }
373 
374 /*
375  * Process an ioctl request.
376  */
377 enioctl(ifp, cmd, data)
378 	register struct ifnet *ifp;
379 	int cmd;
380 	caddr_t data;
381 {
382 	register struct ifaddr *ifa = (struct ifaddr *)data;
383 	register struct en_softc *es = &en_softc[ifp->if_unit];
384 	register struct ensw *esp;
385 	register int family;
386 	int s = splimp(), error = 0;
387 
388 	switch (cmd) {
389 
390 	case SIOCSIFADDR:
391 		ifp->if_flags |= IFF_UP;
392 		eninit(ifp->if_unit);
393 		switch (ifa->ifa_addr->sa_family) {
394 #ifdef INET
395 		case AF_INET:
396 			((struct arpcom *)ifp)->ac_ipaddr =
397 				IA_SIN(ifa)->sin_addr;
398 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
399 			break;
400 #endif
401 		}
402 		break;
403 
404 	case SIOCSIFFLAGS:
405 		if ((ifp->if_flags & IFF_UP) == 0 &&
406 		    es->es_flags & ENF_RUNNING) {
407 			es->es_flags &= ~ENF_RUNNING;
408 		} else if (ifp->if_flags & IFF_UP &&
409 		    (es->es_flags & ENF_RUNNING) == 0)
410 			eninit(ifp->if_unit);
411 #if NBPFILTER > 0
412 		else if (ifp->if_flags & IFF_UP &&
413 		    (ifp->if_flags & IFF_RUNNING) == 0) {
414 			en_prom_mode(ifp->if_unit,
415 				ifp->if_flags & IFF_PROMISC);
416 			ifp->if_flags |= IFF_RUNNING;
417 		}
418 #endif
419 		break;
420 
421 	default:
422 		error = EINVAL;
423 	}
424 	splx(s);
425 	return (error);
426 }
427 
428 /*
429  * set ethernet address for unit
430  */
431 ensetaddr(physaddr, unit)
432 	u_char *physaddr;
433 	int unit;
434 {
435 	register struct en_softc *es = &en_softc[unit];
436 
437 	if (!(es->es_flags & ENF_RUNNING))
438 		return;
439 
440 	bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr);
441 	es->es_flags &= ~ENF_RUNNING;
442 	es->es_flags |= ENF_SETADDR;
443 	eninit(unit);
444 }
445 
446 /*
447  * Machine dependent functions
448  *
449  *	en_probe();
450  *	en_attach();
451  *	en_init();
452  *	enxint();
453  *	enrint();
454  *	en_prom_mode()
455  */
456 #ifdef CPU_SINGLE
457 #include "../include/cpu.h"
458 
459 en_probe(hi)
460 	struct hb_device *hi;
461 {
462 
463 	return (lance_probe(hi->hi_unit));
464 }
465 
466 en_attach(unit)
467 	int unit;
468 {
469 	register struct en_softc *es = &en_softc[unit];
470 	register u_char *p;
471 	register int i;
472 	extern lance_intr();
473 
474 #if !defined(news700) && !defined(mips)
475 	register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr);
476 #endif
477 	if (lance_open(unit) < 0)
478 		printf("lance initialize error\n");
479 	lance_get_addr(unit, (caddr_t)es->es_addr);
480 }
481 
482 en_init(unit)
483 	int unit;
484 {
485 
486 }
487 
488 en_start(unit, len)
489 	int unit;
490 	int len;
491 {
492 
493 	lance_transmit(unit, len);
494 }
495 
496 enxint(unit)
497 	register int unit;
498 {
499 
500 	_enxint(unit, lance_xmit_error(unit), lance_collision(unit));
501 }
502 
503 enrint(unit)
504 	register int unit;
505 {
506 	register struct en_softc *es = &en_softc[unit];
507 	caddr_t get_recv_buffer();
508 
509 	while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) {
510 		_enrint(unit,
511 		    get_recv_length(unit) - sizeof(struct en_rheader));
512 		free_recv_buffer(unit);
513 	}
514 }
515 
516 en_prom_mode(unit, mode)
517 	int unit, mode;
518 {
519 
520 	lance_prom_mode(unit, mode);
521 }
522 #endif /* CPU_SINGLE */
523 
524 #ifdef IPC_MRX
525 #include "../ipc/newsipc.h"
526 #include "../mrx/h/lancereg.h"
527 #include "../mrx/h/lance.h"
528 
529 int	port_enxmit[NEN];
530 int	port_enrecv[NEN];
531 int	port_enctrl[NEN];
532 int	port_enxmit_iop[NEN];
533 int	port_enrecv_iop[NEN];
534 int	port_enctrl_iop[NEN];
535 
536 en_probe(ii)
537 	register struct iop_device *ii;
538 {
539 	int unit = ii->ii_unit;
540 	int lance_func, *reply;
541 	char name[32];
542 	extern char *make_name();
543 
544 	if (port_enrecv[unit] == 0) {
545 
546 #define	PT_CREATE(buf, name, unit, func)	\
547 	port_create(make_name(buf, name, unit), func, unit)
548 #define	OB_QUERY(buf, name, unit) \
549 	object_query(make_name(buf, name, unit))
550 
551 		make_name(name, "@enrecvX", unit);
552 		port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint);
553 		port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint);
554 		port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL);
555 		/* use NULL action port */
556 		port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit);
557 		port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit);
558 		port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit);
559 	}
560 	if (port_enctrl_iop[unit] < 0)
561 		goto bad;
562 	lance_func = EN_START;
563 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
564 	    sizeof(lance_func), 0);
565 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
566 	if (*reply < 0)
567 		goto bad;
568 	lance_func = EN_STOP;
569 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
570 	    sizeof(lance_func), 0);
571 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
572 	return (1);
573 bad:
574 	return (0);
575 }
576 
577 en_attach(unit)
578 	int unit;
579 {
580 	register struct en_softc *es = &en_softc[unit];
581 	int lance_func;
582 	struct ether_addr *ether_addr;
583 
584 	lance_func = EN_GETADDR;
585 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
586 	    sizeof(lance_func), 0);
587 	msg_recv(port_enctrl[unit], NULL, &ether_addr, NULL, 0);
588 	bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr));
589 	msg_free(port_enctrl[unit]);
590 }
591 
592 en_init(unit)
593 	int unit;
594 {
595 	register struct en_softc *es = &en_softc[unit];
596 	register int port;
597 	struct lance_ctrl_req req;
598 	int *reply;
599 
600 	req.lance_func = EN_SETXMITBUF;
601 	mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr,
602 		ETHERMTU + sizeof(struct en_rheader));
603 	msg_send(port_enctrl_iop[unit], port_enctrl[unit],
604 	    &req, sizeof(req), 0);
605 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
606 
607 	req.lance_func = EN_START;
608 	msg_send(port_enctrl_iop[unit], port_enctrl[unit],
609 	    &req, sizeof(req), 0);
610 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
611 	msg_free(port_enctrl[unit]);
612 
613 	msg_send(port_enrecv_iop[unit], port_enrecv[unit],
614 	    es->es_ifnews.ifn_raddr,
615 	    ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
616 }
617 
618 en_start(unit, len)
619 	int unit;
620 	int len;
621 {
622 
623 	msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0);
624 }
625 
626 enxint(unit)
627 	register int unit;
628 {
629 	int *len;
630 	struct en_softc *es = &en_softc[unit];
631 
632 	if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) {
633 		printf("stray enxint\n");
634 		return;
635 	}
636 	if (es->es_ifnews.ifn_mbuf)
637 		m_freem(es->es_ifnews.ifn_mbuf);
638 	_enxint(unit, *len < 0, *len & 0x10000);
639 }
640 
641 enrint(unit)
642 	int unit;
643 {
644 	int len;
645 	int *reply;
646 
647 	if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) {
648 		printf("stray enrint\n");
649 		return;
650 	}
651 	len = *reply - sizeof(struct en_rheader);
652 	msg_free(port_enrecv[unit]);
653 #ifdef mips
654 	/*
655 	 * cache flush address must aligned long word boundary.
656 	 * so, add 3 for sanity.
657 	 */
658 	clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03,
659 	    len + sizeof (struct en_rheader) + 3);
660 #endif
661 	_enrint(unit, len);
662 	msg_send(port_enrecv_iop[unit], port_enrecv[unit],
663 	    en_softc[unit].es_ifnews.ifn_raddr,
664 	    ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
665 }
666 
667 en_prom_mode(unit, mode)
668 	int unit, mode;
669 {
670 	static int port;
671 	struct lance_ctrl_req req;
672 	extern int port_enctrl_iop[];
673 
674 	req.lance_func = EN_PROMMODE;
675 	req.lance_mode = mode;
676 	msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0);
677 }
678 #endif /* IPC_MRX */
679 #endif /* NEN > 0 */
680