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