xref: /original-bsd/sys/vax/if/if_en.c (revision 3f839ad3)
1 /*	if_en.c	4.73	82/11/17	*/
2 
3 #include "en.h"
4 
5 /*
6  * Xerox prototype (3 Mb) Ethernet interface driver.
7  */
8 
9 #include "../h/param.h"
10 #include "../h/systm.h"
11 #include "../h/mbuf.h"
12 #include "../h/pte.h"
13 #include "../h/buf.h"
14 #include "../h/protosw.h"
15 #include "../h/socket.h"
16 #include "../h/vmmac.h"
17 #include <errno.h>
18 
19 #include "../net/if.h"
20 #include "../net/netisr.h"
21 #include "../net/route.h"
22 #include "../netinet/in.h"
23 #include "../netinet/in_systm.h"
24 #include "../netinet/ip.h"
25 #include "../netinet/ip_var.h"
26 #include "../netpup/pup.h"
27 
28 #include "../vax/cpu.h"
29 #include "../vax/mtpr.h"
30 #include "../vaxif/if_en.h"
31 #include "../vaxif/if_enreg.h"
32 #include "../vaxif/if_uba.h"
33 #include "../vaxuba/ubareg.h"
34 #include "../vaxuba/ubavar.h"
35 
36 #define	ENMTU	(1024+512)
37 #define	ENMRU	(1024+512+16)		/* 16 is enough to receive trailer */
38 
39 int	enprobe(), enattach(), enrint(), enxint(), encollide();
40 struct	uba_device *eninfo[NEN];
41 u_short enstd[] = { 0 };
42 struct	uba_driver endriver =
43 	{ enprobe, 0, enattach, 0, enstd, "en", eninfo };
44 #define	ENUNIT(x)	minor(x)
45 
46 int	eninit(),enoutput(),enreset();
47 
48 /*
49  * Ethernet software status per interface.
50  *
51  * Each interface is referenced by a network interface structure,
52  * es_if, which the routing code uses to locate the interface.
53  * This structure contains the output queue for the interface, its address, ...
54  * We also have, for each interface, a UBA interface structure, which
55  * contains information about the UNIBUS resources held by the interface:
56  * map registers, buffered data paths, etc.  Information is cached in this
57  * structure for use by the if_uba.c routines in running the interface
58  * efficiently.
59  */
60 struct	en_softc {
61 	struct	ifnet es_if;		/* network-visible interface */
62 	struct	ifuba es_ifuba;		/* UNIBUS resources */
63 	short	es_delay;		/* current output delay */
64 	short	es_mask;		/* mask for current output delay */
65 	short	es_lastx;		/* host last transmitted to */
66 	short	es_oactive;		/* is output active? */
67 	short	es_olen;		/* length of last output */
68 } en_softc[NEN];
69 
70 /*
71  * Do output DMA to determine interface presence and
72  * interrupt vector.  DMA is too short to disturb other hosts.
73  */
74 enprobe(reg)
75 	caddr_t reg;
76 {
77 	register int br, cvec;		/* r11, r10 value-result */
78 	register struct endevice *addr = (struct endevice *)reg;
79 
80 #ifdef lint
81 	br = 0; cvec = br; br = cvec;
82 	enrint(0); enxint(0); encollide(0);
83 #endif
84 	addr->en_istat = 0;
85 	addr->en_owc = -1;
86 	addr->en_oba = 0;
87 	addr->en_ostat = EN_IEN|EN_GO;
88 	DELAY(100000);
89 	addr->en_ostat = 0;
90 #ifdef ECHACK
91 	br = 0x16;
92 #endif
93 	return (1);
94 }
95 
96 /*
97  * Interface exists: make available by filling in network interface
98  * record.  System will initialize the interface when it is ready
99  * to accept packets.
100  */
101 enattach(ui)
102 	struct uba_device *ui;
103 {
104 	register struct en_softc *es = &en_softc[ui->ui_unit];
105 	register struct sockaddr_in *sin;
106 
107 	es->es_if.if_unit = ui->ui_unit;
108 	es->es_if.if_name = "en";
109 	es->es_if.if_mtu = ENMTU;
110 	es->es_if.if_net = ui->ui_flags;
111 	es->es_if.if_host[0] =
112 	 (~(((struct endevice *)eninfo[ui->ui_unit]->ui_addr)->en_addr)) & 0xff;
113 	sin = (struct sockaddr_in *)&es->es_if.if_addr;
114 	sin->sin_family = AF_INET;
115 	sin->sin_addr = if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]);
116 	sin = (struct sockaddr_in *)&es->es_if.if_broadaddr;
117 	sin->sin_family = AF_INET;
118 	sin->sin_addr = if_makeaddr(es->es_if.if_net, 0);
119 	es->es_if.if_flags = IFF_BROADCAST;
120 	es->es_if.if_init = eninit;
121 	es->es_if.if_output = enoutput;
122 	es->es_if.if_reset = enreset;
123 	es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
124 #if defined(VAX750)
125 	/* don't chew up 750 bdp's */
126 	if (cpu == VAX_750 && ui->ui_unit > 0)
127 		es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP;
128 #endif
129 	if_attach(&es->es_if);
130 }
131 
132 /*
133  * Reset of interface after UNIBUS reset.
134  * If interface is on specified uba, reset its state.
135  */
136 enreset(unit, uban)
137 	int unit, uban;
138 {
139 	register struct uba_device *ui;
140 
141 	if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
142 	    ui->ui_ubanum != uban)
143 		return;
144 	printf(" en%d", unit);
145 	eninit(unit);
146 }
147 
148 /*
149  * Initialization of interface; clear recorded pending
150  * operations, and reinitialize UNIBUS usage.
151  */
152 eninit(unit)
153 	int unit;
154 {
155 	register struct en_softc *es = &en_softc[unit];
156 	register struct uba_device *ui = eninfo[unit];
157 	register struct endevice *addr;
158 	int s;
159 
160 	if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
161 	    sizeof (struct en_header), (int)btoc(ENMRU)) == 0) {
162 		printf("en%d: can't initialize\n", unit);
163 		es->es_if.if_flags &= ~IFF_UP;
164 		return;
165 	}
166 	addr = (struct endevice *)ui->ui_addr;
167 	addr->en_istat = addr->en_ostat = 0;
168 
169 	/*
170 	 * Hang a receive and start any
171 	 * pending writes by faking a transmit complete.
172 	 */
173 	s = splimp();
174 	addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
175 	addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
176 	addr->en_istat = EN_IEN|EN_GO;
177 	es->es_oactive = 1;
178 	es->es_if.if_flags |= IFF_UP;
179 	enxint(unit);
180 	splx(s);
181 	if_rtinit(&es->es_if, RTF_UP);
182 }
183 
184 int	enalldelay = 0;
185 int	enlastdel = 50;
186 int	enlastmask = (~0) << 5;
187 
188 /*
189  * Start or restart output on interface.
190  * If interface is already active, then this is a retransmit
191  * after a collision, and just restuff registers and delay.
192  * If interface is not already active, get another datagram
193  * to send off of the interface queue, and map it to the interface
194  * before starting the output.
195  */
196 enstart(dev)
197 	dev_t dev;
198 {
199         int unit = ENUNIT(dev);
200 	struct uba_device *ui = eninfo[unit];
201 	register struct en_softc *es = &en_softc[unit];
202 	register struct endevice *addr;
203 	struct mbuf *m;
204 	int dest;
205 
206 	if (es->es_oactive)
207 		goto restart;
208 
209 	/*
210 	 * Not already active: dequeue another request
211 	 * and map it to the UNIBUS.  If no more requests,
212 	 * just return.
213 	 */
214 	IF_DEQUEUE(&es->es_if.if_snd, m);
215 	if (m == 0) {
216 		es->es_oactive = 0;
217 		return;
218 	}
219 	dest = mtod(m, struct en_header *)->en_dhost;
220 	es->es_olen = if_wubaput(&es->es_ifuba, m);
221 
222 	/*
223 	 * Ethernet cannot take back-to-back packets (no
224 	 * buffering in interface.  To help avoid overrunning
225 	 * receivers, enforce a small delay (about 1ms) in interface:
226 	 *	* between all packets when enalldelay
227 	 *	* whenever last packet was broadcast
228 	 *	* whenever this packet is to same host as last packet
229 	 */
230 	if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
231 		es->es_delay = enlastdel;
232 		es->es_mask = enlastmask;
233 	}
234 	es->es_lastx = dest;
235 
236 restart:
237 	/*
238 	 * Have request mapped to UNIBUS for transmission.
239 	 * Purge any stale data from this BDP, and start the otput.
240 	 */
241 	if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
242 		UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
243 	addr = (struct endevice *)ui->ui_addr;
244 	addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
245 	addr->en_odelay = es->es_delay;
246 	addr->en_owc = -((es->es_olen + 1) >> 1);
247 	addr->en_ostat = EN_IEN|EN_GO;
248 	es->es_oactive = 1;
249 }
250 
251 /*
252  * Ethernet interface transmitter interrupt.
253  * Start another output if more data to send.
254  */
255 enxint(unit)
256 	int unit;
257 {
258 	register struct uba_device *ui = eninfo[unit];
259 	register struct en_softc *es = &en_softc[unit];
260 	register struct endevice *addr = (struct endevice *)ui->ui_addr;
261 
262 	if (es->es_oactive == 0)
263 		return;
264 	if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
265 		es->es_if.if_oerrors++;
266 		endocoll(unit);
267 		return;
268 	}
269 	es->es_if.if_opackets++;
270 	es->es_oactive = 0;
271 	es->es_delay = 0;
272 	es->es_mask = ~0;
273 	if (es->es_ifuba.ifu_xtofree) {
274 		m_freem(es->es_ifuba.ifu_xtofree);
275 		es->es_ifuba.ifu_xtofree = 0;
276 	}
277 	if (es->es_if.if_snd.ifq_head == 0) {
278 		es->es_lastx = 256;		/* putatively illegal */
279 		return;
280 	}
281 	enstart(unit);
282 }
283 
284 /*
285  * Collision on ethernet interface.  Do exponential
286  * backoff, and retransmit.  If have backed off all
287  * the way print warning diagnostic, and drop packet.
288  */
289 encollide(unit)
290 	int unit;
291 {
292 	struct en_softc *es = &en_softc[unit];
293 
294 	es->es_if.if_collisions++;
295 	if (es->es_oactive == 0)
296 		return;
297 	endocoll(unit);
298 }
299 
300 endocoll(unit)
301 	int unit;
302 {
303 	register struct en_softc *es = &en_softc[unit];
304 
305 	/*
306 	 * Es_mask is a 16 bit number with n low zero bits, with
307 	 * n the number of backoffs.  When es_mask is 0 we have
308 	 * backed off 16 times, and give up.
309 	 */
310 	if (es->es_mask == 0) {
311 		printf("en%d: send error\n", unit);
312 		enxint(unit);
313 		return;
314 	}
315 	/*
316 	 * Another backoff.  Restart with delay based on n low bits
317 	 * of the interval timer.
318 	 */
319 	es->es_mask <<= 1;
320 	es->es_delay = mfpr(ICR) &~ es->es_mask;
321 	enstart(unit);
322 }
323 
324 struct	sockaddr_pup pupsrc = { AF_PUP };
325 struct	sockaddr_pup pupdst = { AF_PUP };
326 struct	sockproto pupproto = { PF_PUP };
327 /*
328  * Ethernet interface receiver interrupt.
329  * If input error just drop packet.
330  * Otherwise purge input buffered data path and examine
331  * packet to determine type.  If can't determine length
332  * from type, then have to drop packet.  Othewise decapsulate
333  * packet based on type and pass to type specific higher-level
334  * input routine.
335  */
336 enrint(unit)
337 	int unit;
338 {
339 	register struct en_softc *es = &en_softc[unit];
340 	struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
341 	register struct en_header *en;
342     	struct mbuf *m;
343 	int len; short resid;
344 	register struct ifqueue *inq;
345 	int off;
346 
347 	es->es_if.if_ipackets++;
348 
349 	/*
350 	 * Purge BDP; drop if input error indicated.
351 	 */
352 	if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
353 		UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
354 	if (addr->en_istat&EN_IERROR) {
355 		es->es_if.if_ierrors++;
356 		goto setup;
357 	}
358 
359 	/*
360 	 * Calculate input data length.
361 	 * Get pointer to ethernet header (in input buffer).
362 	 * Deal with trailer protocol: if type is PUP trailer
363 	 * get true type from first 16-bit word past data.
364 	 * Remember that type was trailer by setting off.
365 	 */
366 	resid = addr->en_iwc;
367 	if (resid)
368 		resid |= 0176000;
369 	len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
370 	len -= sizeof (struct en_header);
371 	if (len > ENMRU)
372 		goto setup;			/* sanity */
373 	en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
374 #define	endataaddr(en, off, type)	((type)(((caddr_t)((en)+1)+(off))))
375 	if (en->en_type >= ENPUP_TRAIL &&
376 	    en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
377 		off = (en->en_type - ENPUP_TRAIL) * 512;
378 		if (off > ENMTU)
379 			goto setup;		/* sanity */
380 		en->en_type = *endataaddr(en, off, u_short *);
381 		resid = *(endataaddr(en, off+2, u_short *));
382 		if (off + resid > len)
383 			goto setup;		/* sanity */
384 		len = off + resid;
385 	} else
386 		off = 0;
387 	if (len == 0)
388 		goto setup;
389 	/*
390 	 * Pull packet off interface.  Off is nonzero if packet
391 	 * has trailing header; if_rubaget will then force this header
392 	 * information to be at the front, but we still have to drop
393 	 * the type and length which are at the front of any trailer data.
394 	 */
395 	m = if_rubaget(&es->es_ifuba, len, off);
396 	if (m == 0)
397 		goto setup;
398 	if (off) {
399 		m->m_off += 2 * sizeof (u_short);
400 		m->m_len -= 2 * sizeof (u_short);
401 	}
402 	switch (en->en_type) {
403 
404 #ifdef INET
405 	case ENPUP_IPTYPE:
406 		schednetisr(NETISR_IP);
407 		inq = &ipintrq;
408 		break;
409 #endif
410 #ifdef PUP
411 	case ENPUP_PUPTYPE: {
412 		struct pup_header *pup = mtod(m, struct pup_header *);
413 
414 		pupproto.sp_protocol = pup->pup_type;
415 		pupdst.spup_addr = pup->pup_dport;
416 		pupsrc.spup_addr = pup->pup_sport;
417 		raw_input(m, &pupproto, (struct sockaddr *)&pupsrc,
418 		  (struct sockaddr *)&pupdst);
419 		goto setup;
420 	}
421 #endif
422 	default:
423 		m_freem(m);
424 		goto setup;
425 	}
426 
427 	if (IF_QFULL(inq)) {
428 		IF_DROP(inq);
429 		m_freem(m);
430 	} else
431 		IF_ENQUEUE(inq, m);
432 
433 setup:
434 	/*
435 	 * Reset for next packet.
436 	 */
437 	addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
438 	addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
439 	addr->en_istat = EN_IEN|EN_GO;
440 }
441 
442 /*
443  * Ethernet output routine.
444  * Encapsulate a packet of type family for the local net.
445  * Use trailer local net encapsulation if enough data in first
446  * packet leaves a multiple of 512 bytes of data in remainder.
447  */
448 enoutput(ifp, m0, dst)
449 	struct ifnet *ifp;
450 	struct mbuf *m0;
451 	struct sockaddr *dst;
452 {
453 	int type, dest, s, error;
454 	register struct mbuf *m = m0;
455 	register struct en_header *en;
456 	register int off;
457 
458 	switch (dst->sa_family) {
459 
460 #ifdef INET
461 	case AF_INET:
462 		dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
463 		if (in_lnaof(*((struct in_addr *)&dest)) >= 0x100) {
464 			error = EPERM;		/* ??? */
465 			goto bad;
466 		}
467 		dest = (dest >> 24) & 0xff;
468 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
469 		if (off > 0 && (off & 0x1ff) == 0 &&
470 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
471 			type = ENPUP_TRAIL + (off>>9);
472 			m->m_off -= 2 * sizeof (u_short);
473 			m->m_len += 2 * sizeof (u_short);
474 			*mtod(m, u_short *) = ENPUP_IPTYPE;
475 			*(mtod(m, u_short *) + 1) = m->m_len;
476 			goto gottrailertype;
477 		}
478 		type = ENPUP_IPTYPE;
479 		off = 0;
480 		goto gottype;
481 #endif
482 #ifdef PUP
483 	case AF_PUP:
484 		dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host;
485 		type = ENPUP_PUPTYPE;
486 		off = 0;
487 		goto gottype;
488 #endif
489 
490 	default:
491 		printf("en%d: can't handle af%d\n", ifp->if_unit,
492 			dst->sa_family);
493 		error = EAFNOSUPPORT;
494 		goto bad;
495 	}
496 
497 gottrailertype:
498 	/*
499 	 * Packet to be sent as trailer: move first packet
500 	 * (control information) to end of chain.
501 	 */
502 	while (m->m_next)
503 		m = m->m_next;
504 	m->m_next = m0;
505 	m = m0->m_next;
506 	m0->m_next = 0;
507 	m0 = m;
508 
509 gottype:
510 	/*
511 	 * Add local net header.  If no space in first mbuf,
512 	 * allocate another.
513 	 */
514 	if (m->m_off > MMAXOFF ||
515 	    MMINOFF + sizeof (struct en_header) > m->m_off) {
516 		m = m_get(M_DONTWAIT);
517 		if (m == 0) {
518 			error = ENOBUFS;
519 			goto bad;
520 		}
521 		m->m_next = m0;
522 		m->m_off = MMINOFF;
523 		m->m_len = sizeof (struct en_header);
524 	} else {
525 		m->m_off -= sizeof (struct en_header);
526 		m->m_len += sizeof (struct en_header);
527 	}
528 	en = mtod(m, struct en_header *);
529 	en->en_shost = ifp->if_host[0];
530 	en->en_dhost = dest;
531 	en->en_type = type;
532 
533 	/*
534 	 * Queue message on interface, and start output if interface
535 	 * not yet active.
536 	 */
537 	s = splimp();
538 	if (IF_QFULL(&ifp->if_snd)) {
539 		IF_DROP(&ifp->if_snd);
540 		error = ENOBUFS;
541 		goto qfull;
542 	}
543 	IF_ENQUEUE(&ifp->if_snd, m);
544 	if (en_softc[ifp->if_unit].es_oactive == 0)
545 		enstart(ifp->if_unit);
546 	splx(s);
547 	return (0);
548 qfull:
549 	m0 = m;
550 	splx(s);
551 bad:
552 	m_freem(m0);
553 	return (error);
554 }
555