xref: /original-bsd/sys/news3400/if/if_en.c (revision e58d00f4)
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.5 (Berkeley) 07/01/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(),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 
89 #if NBPFILTER > 0
90 #include "../net/bpf.h"
91 #endif
92 
93 enprobe(ii)
94 	struct iop_device *ii;
95 {
96 
97 	return (en_probe(ii));
98 }
99 
100 /*
101  * Interface exists: make available by filling in network interface
102  * record.  System will initialize the interface when it is ready
103  * to accept packets.  A STATUS command is done to get the ethernet
104  * address and other interesting data.
105  */
106 enattach(ii)
107 	register struct iop_device *ii;
108 {
109 	register struct en_softc *es = &en_softc[ii->ii_unit];
110 	register struct ifnet *ifp = &es->es_if;
111 	extern char *ether_sprintf();
112 
113 	en_attach(ii->ii_unit);
114 	printf("en%d: hardware address %s\n",
115 		ii->ii_unit, ether_sprintf((u_char *)es->es_addr));
116 	ifp->if_unit = ii->ii_unit;
117 	ifp->if_name = "en";
118 	ifp->if_mtu = ETHERMTU;
119 	ifp->if_init = eninit;
120 	ifp->if_ioctl = enioctl;
121 	ifp->if_output = ether_output;
122 #ifdef NOTDEF /* KU:XXX if_reset is obsolete */
123 	ifp->if_reset = enreset;
124 #endif
125 	ifp->if_start = enstart;
126 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
127 #if NBPFILTER > 0
128 	bpfattach(&es->es_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
129 #endif
130 	if_attach(ifp);
131 }
132 
133 /*
134  * Reset of interface after IOP reset.
135  */
136 enreset(unit)
137 	int unit;
138 {
139 	register struct iop_device *ii;
140 
141 	if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0)
142 		return;
143 	printf(" en%d", unit);
144 	en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
145 	en_softc[unit].es_flags &= ~ENF_RUNNING;
146 	eninit(unit);
147 }
148 
149 /*
150  * Initialization of interface; clear recorded pending
151  * operations, and reinitialize IOP usage.
152  */
153 eninit(unit)
154 	int unit;
155 {
156 	register struct en_softc *es = &en_softc[unit];
157 	register struct ifnet *ifp = &es->es_if;
158 	int s;
159 
160 	/* not yet, if address still unknown */
161 	if (ifp->if_addrlist == (struct ifaddr *)0)
162 		return;
163 	if (es->es_flags & ENF_RUNNING)
164 		return;
165 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
166 		if (if_newsinit(&es->es_ifnews,
167 		    sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) {
168 			printf("en%d: can't initialize\n", unit);
169 			es->es_if.if_flags &= ~IFF_UP;
170 			return;
171 		}
172 		ifp->if_watchdog = enwatch;
173 		es->es_interval = ENWATCHINTERVAL;
174 		ifp->if_timer = es->es_interval;
175 		s = splimp();
176 		en_init(unit);
177 		splx(s);
178 	}
179 	es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS;
180 	es->es_flags |= ENF_RUNNING;
181 }
182 
183 /*
184  * Start output on interface.
185  * Get another datagram to send off of the interface queue,
186  * and map it to the interface before starting the output.
187  */
188 enstart(ifp)
189 	register struct ifnet *ifp;
190 {
191         int unit = ifp->if_unit, len;
192 	register struct en_softc *es = &en_softc[unit];
193 	register struct mbuf *m;
194 	int s;
195 
196 	IF_DEQUEUE(&es->es_if.if_snd, m);
197 	if (m == 0)
198 		return(0);
199 #ifdef CPU_SINGLE
200 	es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit);
201 #endif
202 	len = if_wnewsput(&es->es_ifnews, m);
203 	/*
204 	 * Ensure minimum packet length.
205 	 * This makes the safe assumtion that there are no virtual holes
206 	 * after the data.
207 	 * For security, it might be wise to zero out the added bytes,
208 	 * but we're mainly interested in speed at the moment.
209 	 */
210 	if (len - sizeof(struct ether_header) < ETHERMIN)
211 		len = ETHERMIN + sizeof(struct ether_header);
212 	s = splclock();			/* KU:XXX should be gone */
213 	en_start(unit, len);
214 	es->es_if.if_flags |= IFF_OACTIVE;
215 	(void) splx(s);			/* KU:XXX */
216 #if NBPFILTER > 0
217 	/*
218 	 * If bpf is listening on this interface, let it
219 	 * see the packet before we commit it to the wire.
220 	 */
221 	if (es->es_bpf) {
222 #ifdef CPU_SINGLE
223 		bpf_tap(es->es_bpf, es->es_ifnews.ifn_waddr, len);
224 #else
225 		bpf_mtap(es->es_bpf, m);
226 #endif
227 	}
228 #endif /* NBPFILTER > 0 */
229 	return(0);
230 }
231 
232 /*
233  * Transmit done interrupt.
234  */
235 _enxint(unit, error, collision)
236 	int unit;
237 	int error, collision;
238 {
239 	register struct en_softc *es = &en_softc[unit];
240 
241 #ifdef notyet /* KU:XXX */
242 	intrcnt[INTR_ETHER0 + unit]++;
243 #endif
244 	if ((es->es_if.if_flags & IFF_OACTIVE) == 0) {
245 		printf("en%d: stray xmit interrupt\n", unit);
246 		return;
247 	} else {
248 		es->es_if.if_flags &= ~IFF_OACTIVE;
249 		es->es_if.if_opackets++;
250 	}
251 	if (error) {
252 #ifdef DEBUG
253 		printf("_enxint: error (unit=%d)\n", unit);
254 #endif
255 		es->es_if.if_oerrors++;
256 	}
257 	if (collision) {
258 #ifdef DEBUG
259 		printf("_enxint: collision (unit=%d)\n", unit);
260 #endif
261 		es->es_if.if_collisions++;
262 	}
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 #if defined(mips) && defined(CPU_SINGLE)
287 	int bxcopy();
288 #endif
289 
290 #ifdef notyet /* KU:XXX */
291 	intrcnt[INTR_ETHER0 + unit]++;
292 #endif
293 	es->es_if.if_ipackets++;
294 	if ((es->es_flags & ENF_RUNNING) == 0)
295 		return;
296 	en = (struct en_rheader *)(es->es_ifnews.ifn_raddr);
297 	if (len < ETHERMIN || len > ETHERMTU) {
298 		es->es_if.if_ierrors++;
299 		return;
300 	}
301 #if NBPFILTER > 0
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 (es->es_bpf) {
307 		bpf_tap(es->es_bpf, 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 #endif /* NBPFILTER > 0 */
324 	/*
325 	 * Deal with trailer protocol: if type is trailer type
326 	 * get true type from first 16-bit word past data.
327 	 * Remember that type was trailer by setting off.
328 	 */
329 	en->enr_type = ntohs((u_short)en->enr_type);
330 #define	endataaddr(en, off, type)	((type)(((caddr_t)((en)+1)+(off))))
331 	if (en->enr_type >= ETHERTYPE_TRAIL &&
332 	    en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
333 		off = (en->enr_type - ETHERTYPE_TRAIL) * 512;
334 		if (off >= ETHERMTU)
335 			return;
336 		en->enr_type = ntohs(*endataaddr(en, off, u_short *));
337 		resid = ntohs(*(endataaddr(en, off+2, u_short *)));
338 		if (off + resid > len)
339 			return;
340 		len = off + resid;
341 	} else
342 		off = 0;
343 	/*
344 	 * Pull packet off interface.  Off is nonzero if packet
345 	 * has trailing header; m_devget will then force this header
346 	 * information to be at the front, but we still have to drop
347 	 * the type and length which are at the front of any trailer data.
348 	 * KU:XXX really?
349 	 */
350 	type = en->enr_type;
351 #if defined(mips) && defined(CPU_SINGLE)
352 	m = m_devget((char *)(en + 1), len, off, &es->es_if, bxcopy);
353 #else
354 	m = m_devget((char *)(en + 1), len, off, &es->es_if, 0);
355 #endif
356 	if (m == 0)
357 		return;
358 	ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m);
359 }
360 
361 /*
362  * Watchdog routine, request statistics from board.
363  */
364 enwatch(unit)
365 	int unit;
366 {
367 	register struct en_softc *es = &en_softc[unit];
368 	register struct ifnet *ifp = &es->es_if;
369 
370 	ifp->if_timer = es->es_interval;
371 }
372 
373 /*
374  * Process an ioctl request.
375  */
376 enioctl(ifp, cmd, data)
377 	register struct ifnet *ifp;
378 	int cmd;
379 	caddr_t data;
380 {
381 	register struct ifaddr *ifa = (struct ifaddr *)data;
382 	register struct en_softc *es = &en_softc[ifp->if_unit];
383 	register struct ensw *esp;
384 	register int family;
385 	int s = splimp(), error = 0;
386 
387 	switch (cmd) {
388 
389 	case SIOCSIFADDR:
390 		ifp->if_flags |= IFF_UP;
391 		eninit(ifp->if_unit);
392 		switch (ifa->ifa_addr->sa_family) {
393 #ifdef INET
394 		case AF_INET:
395 			((struct arpcom *)ifp)->ac_ipaddr =
396 				IA_SIN(ifa)->sin_addr;
397 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
398 			break;
399 #endif
400 		}
401 		break;
402 
403 	case SIOCSIFFLAGS:
404 		if ((ifp->if_flags & IFF_UP) == 0 &&
405 		    es->es_flags & ENF_RUNNING) {
406 			es->es_flags &= ~ENF_RUNNING;
407 		} else if (ifp->if_flags & IFF_UP &&
408 		    (es->es_flags & ENF_RUNNING) == 0)
409 			eninit(ifp->if_unit);
410 #if NBPFILTER > 0
411 		else if (ifp->if_flags & IFF_UP &&
412 		    (ifp->if_flags & IFF_RUNNING) == 0) {
413 			en_prom_mode(ifp->if_unit,
414 				ifp->if_flags & IFF_PROMISC);
415 			ifp->if_flags |= IFF_RUNNING;
416 		}
417 #endif
418 		break;
419 
420 	default:
421 		error = EINVAL;
422 	}
423 	splx(s);
424 	return (error);
425 }
426 
427 /*
428  * set ethernet address for unit
429  */
430 ensetaddr(physaddr, unit)
431 	u_char *physaddr;
432 	int unit;
433 {
434 	register struct en_softc *es = &en_softc[unit];
435 
436 	if (!(es->es_flags & ENF_RUNNING))
437 		return;
438 
439 	bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr);
440 	es->es_flags &= ~ENF_RUNNING;
441 	es->es_flags |= ENF_SETADDR;
442 	eninit(unit);
443 }
444 
445 /*
446  * Machine dependent functions
447  *
448  *	en_probe();
449  *	en_attach();
450  *	en_init();
451  *	enxint();
452  *	enrint();
453  *	en_prom_mode()
454  */
455 #ifdef CPU_SINGLE
456 #include "../include/cpu.h"
457 
458 en_probe(hi)
459 	struct hb_device *hi;
460 {
461 
462 	return (lance_probe(hi->hi_unit));
463 }
464 
465 en_attach(unit)
466 	int unit;
467 {
468 	register struct en_softc *es = &en_softc[unit];
469 	register u_char *p;
470 	register int i;
471 	extern lance_intr();
472 
473 #if !defined(news700) && !defined(mips)
474 	register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr);
475 #endif
476 	if (lance_open(unit) < 0)
477 		printf("lance initialize error\n");
478 	lance_get_addr(unit, (caddr_t)es->es_addr);
479 }
480 
481 en_init(unit)
482 	int unit;
483 {
484 
485 }
486 
487 en_start(unit, len)
488 	int unit;
489 	int len;
490 {
491 
492 	lance_transmit(unit, len);
493 }
494 
495 enxint(unit)
496 	register int unit;
497 {
498 
499 	_enxint(unit, lance_xmit_error(unit), lance_collision(unit));
500 }
501 
502 enrint(unit)
503 	register int unit;
504 {
505 	register struct en_softc *es = &en_softc[unit];
506 	caddr_t get_recv_buffer();
507 
508 	while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) {
509 		_enrint(unit,
510 		    get_recv_length(unit) - sizeof(struct en_rheader));
511 		free_recv_buffer(unit);
512 	}
513 }
514 
515 en_prom_mode(unit, mode)
516 	int unit, mode;
517 {
518 
519 	lance_prom_mode(unit, mode);
520 }
521 #endif /* CPU_SINGLE */
522 
523 #ifdef IPC_MRX
524 #include "../ipc/newsipc.h"
525 #include "../mrx/h/lancereg.h"
526 #include "../mrx/h/lance.h"
527 
528 int	port_enxmit[NEN];
529 int	port_enrecv[NEN];
530 int	port_enctrl[NEN];
531 int	port_enxmit_iop[NEN];
532 int	port_enrecv_iop[NEN];
533 int	port_enctrl_iop[NEN];
534 
535 en_probe(ii)
536 	register struct iop_device *ii;
537 {
538 	int unit = ii->ii_unit;
539 	int lance_func, *reply;
540 	char name[32];
541 	extern char *make_name();
542 
543 	if (port_enrecv[unit] == 0) {
544 
545 #define	PT_CREATE(buf, name, unit, func)	\
546 	port_create(make_name(buf, name, unit), func, unit)
547 #define	OB_QUERY(buf, name, unit) \
548 	object_query(make_name(buf, name, unit))
549 
550 		make_name(name, "@enrecvX", unit);
551 		port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint);
552 		port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint);
553 		port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL);
554 		/* use NULL action port */
555 		port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit);
556 		port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit);
557 		port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit);
558 	}
559 	if (port_enctrl_iop[unit] < 0)
560 		goto bad;
561 	lance_func = EN_START;
562 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
563 	    sizeof(lance_func), 0);
564 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
565 	if (*reply < 0)
566 		goto bad;
567 	lance_func = EN_STOP;
568 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
569 	    sizeof(lance_func), 0);
570 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
571 	return (1);
572 bad:
573 	return (0);
574 }
575 
576 en_attach(unit)
577 	int unit;
578 {
579 	register struct en_softc *es = &en_softc[unit];
580 	int lance_func;
581 	struct ether_addr *ether_addr;
582 
583 	lance_func = EN_GETADDR;
584 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
585 	    sizeof(lance_func), 0);
586 	msg_recv(port_enctrl[unit], NULL, &ether_addr, NULL, 0);
587 	bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr));
588 	msg_free(port_enctrl[unit]);
589 }
590 
591 en_init(unit)
592 	int unit;
593 {
594 	register struct en_softc *es = &en_softc[unit];
595 	register int port;
596 	struct lance_ctrl_req req;
597 	int *reply;
598 
599 	req.lance_func = EN_SETXMITBUF;
600 	mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr,
601 		ETHERMTU + sizeof(struct en_rheader));
602 	msg_send(port_enctrl_iop[unit], port_enctrl[unit],
603 	    &req, sizeof(req), 0);
604 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
605 
606 	req.lance_func = EN_START;
607 	msg_send(port_enctrl_iop[unit], port_enctrl[unit],
608 	    &req, sizeof(req), 0);
609 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
610 	msg_free(port_enctrl[unit]);
611 
612 	msg_send(port_enrecv_iop[unit], port_enrecv[unit],
613 	    es->es_ifnews.ifn_raddr,
614 	    ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
615 }
616 
617 en_start(unit, len)
618 	int unit;
619 	int len;
620 {
621 
622 	msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0);
623 }
624 
625 enxint(unit)
626 	register int unit;
627 {
628 	int *len;
629 	struct en_softc *es = &en_softc[unit];
630 
631 	if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) {
632 		printf("stray enxint\n");
633 		return;
634 	}
635 	if (es->es_ifnews.ifn_mbuf)
636 		m_freem(es->es_ifnews.ifn_mbuf);
637 	_enxint(unit, *len < 0, *len & 0x10000);
638 }
639 
640 enrint(unit)
641 	int unit;
642 {
643 	int len;
644 	int *reply;
645 
646 	if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) {
647 		printf("stray enrint\n");
648 		return;
649 	}
650 	len = *reply - sizeof(struct en_rheader);
651 	msg_free(port_enrecv[unit]);
652 #ifdef mips
653 	/*
654 	 * cache flush address must aligned long word boundary.
655 	 * so, add 3 for sanity.
656 	 */
657 	clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03,
658 	    len + sizeof (struct en_rheader) + 3);
659 #endif
660 	_enrint(unit, len);
661 	msg_send(port_enrecv_iop[unit], port_enrecv[unit],
662 	    en_softc[unit].es_ifnews.ifn_raddr,
663 	    ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
664 }
665 
666 en_prom_mode(unit, mode)
667 	int unit, mode;
668 {
669 	static int port;
670 	struct lance_ctrl_req req;
671 	extern int port_enctrl_iop[];
672 
673 	req.lance_func = EN_PROMMODE;
674 	req.lance_mode = mode;
675 	msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0);
676 }
677 #endif /* IPC_MRX */
678 #endif /* NEN > 0 */
679