|
|
1.1 root 1: /* if_en.c 6.1 83/07/29 */
2:
3: #include "en.h"
4:
5: /*
6: * Xerox prototype (3 Mb) Ethernet interface driver.
7: */
8: #include "../machine/pte.h"
9:
10: #include "../h/param.h"
11: #include "../h/systm.h"
12: #include "../h/mbuf.h"
13: #include "../h/buf.h"
14: #include "../h/protosw.h"
15: #include "../h/socket.h"
16: #include "../h/vmmac.h"
17: #include "../h/errno.h"
18: #include "../h/ioctl.h"
19:
20: #include "../net/if.h"
21: #include "../net/netisr.h"
22: #include "../net/route.h"
23: #include "../netinet/in.h"
24: #include "../netinet/in_systm.h"
25: #include "../netinet/ip.h"
26: #include "../netinet/ip_var.h"
27: #include "../netpup/pup.h"
28: #include "../netpup/ether.h"
29:
30: #include "../vax/cpu.h"
31: #include "../vax/mtpr.h"
32: #include "../vaxif/if_en.h"
33: #include "../vaxif/if_enreg.h"
34: #include "../vaxif/if_uba.h"
35: #include "../vaxuba/ubareg.h"
36: #include "../vaxuba/ubavar.h"
37:
38: #define ENMTU (1024+512)
39: #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */
40:
41: int enprobe(), enattach(), enrint(), enxint(), encollide();
42: struct uba_device *eninfo[NEN];
43: u_short enstd[] = { 0 };
44: struct uba_driver endriver =
45: { enprobe, 0, enattach, 0, enstd, "en", eninfo };
46: #define ENUNIT(x) minor(x)
47:
48: int eninit(),enoutput(),enreset(),enioctl();
49:
50: #ifdef notdef
51: /*
52: * If you need to byte swap IP's in the system, define
53: * this and do a SIOCSIFFLAGS at boot time.
54: */
55: #define ENF_SWABIPS 0x100
56: #endif
57:
58: /*
59: * Ethernet software status per interface.
60: *
61: * Each interface is referenced by a network interface structure,
62: * es_if, which the routing code uses to locate the interface.
63: * This structure contains the output queue for the interface, its address, ...
64: * We also have, for each interface, a UBA interface structure, which
65: * contains information about the UNIBUS resources held by the interface:
66: * map registers, buffered data paths, etc. Information is cached in this
67: * structure for use by the if_uba.c routines in running the interface
68: * efficiently.
69: */
70: struct en_softc {
71: struct ifnet es_if; /* network-visible interface */
72: struct ifuba es_ifuba; /* UNIBUS resources */
73: short es_delay; /* current output delay */
74: short es_mask; /* mask for current output delay */
75: short es_lastx; /* host last transmitted to */
76: short es_oactive; /* is output active? */
77: short es_olen; /* length of last output */
78: } en_softc[NEN];
79:
80: /*
81: * Do output DMA to determine interface presence and
82: * interrupt vector. DMA is too short to disturb other hosts.
83: */
84: enprobe(reg)
85: caddr_t reg;
86: {
87: register int br, cvec; /* r11, r10 value-result */
88: register struct endevice *addr = (struct endevice *)reg;
89:
90: #ifdef lint
91: br = 0; cvec = br; br = cvec;
92: enrint(0); enxint(0); encollide(0);
93: #endif
94: addr->en_istat = 0;
95: addr->en_owc = -1;
96: addr->en_oba = 0;
97: addr->en_ostat = EN_IEN|EN_GO;
98: DELAY(100000);
99: addr->en_ostat = 0;
100: return (1);
101: }
102:
103: /*
104: * Interface exists: make available by filling in network interface
105: * record. System will initialize the interface when it is ready
106: * to accept packets.
107: */
108: enattach(ui)
109: struct uba_device *ui;
110: {
111: register struct en_softc *es = &en_softc[ui->ui_unit];
112:
113: es->es_if.if_unit = ui->ui_unit;
114: es->es_if.if_name = "en";
115: es->es_if.if_mtu = ENMTU;
116: es->es_if.if_init = eninit;
117: es->es_if.if_output = enoutput;
118: es->es_if.if_ioctl = enioctl;
119: es->es_if.if_reset = enreset;
120: es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
121: #if defined(VAX750)
122: /* don't chew up 750 bdp's */
123: if (cpu == VAX_750 && ui->ui_unit > 0)
124: es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP;
125: #endif
126: if_attach(&es->es_if);
127: }
128:
129: /*
130: * Reset of interface after UNIBUS reset.
131: * If interface is on specified uba, reset its state.
132: */
133: enreset(unit, uban)
134: int unit, uban;
135: {
136: register struct uba_device *ui;
137:
138: if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
139: ui->ui_ubanum != uban)
140: return;
141: printf(" en%d", unit);
142: eninit(unit);
143: }
144:
145: /*
146: * Initialization of interface; clear recorded pending
147: * operations, and reinitialize UNIBUS usage.
148: */
149: eninit(unit)
150: int unit;
151: {
152: register struct en_softc *es = &en_softc[unit];
153: register struct uba_device *ui = eninfo[unit];
154: register struct endevice *addr;
155: struct sockaddr_in *sin = (struct sockaddr_in *)&es->es_if.if_addr;
156: int s;
157:
158: if (in_netof(sin->sin_addr) == 0)
159: return;
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|IFF_RUNNING;
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: #ifdef ENF_SWABIPS
222: /*
223: * The Xerox interface does word at a time DMA, so
224: * someone must do byte swapping of user data if high
225: * and low ender machines are to communicate. It doesn't
226: * belong here, but certain people depend on it, so...
227: *
228: * Should swab everybody, but this is a kludge anyway.
229: */
230: if (es->es_if.if_flags & ENF_SWABIPS) {
231: register struct en_header *en;
232:
233: en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr;
234: if (en->en_type == ENTYPE_IP)
235: enswab((caddr_t)(en + 1), (caddr_t)(en + 1),
236: es->es_olen - sizeof (struct en_header) + 1);
237: }
238: #endif
239:
240: /*
241: * Ethernet cannot take back-to-back packets (no
242: * buffering in interface. To help avoid overrunning
243: * receivers, enforce a small delay (about 1ms) in interface:
244: * * between all packets when enalldelay
245: * * whenever last packet was broadcast
246: * * whenever this packet is to same host as last packet
247: */
248: if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
249: es->es_delay = enlastdel;
250: es->es_mask = enlastmask;
251: }
252: es->es_lastx = dest;
253:
254: restart:
255: /*
256: * Have request mapped to UNIBUS for transmission.
257: * Purge any stale data from this BDP, and start the otput.
258: */
259: if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
260: UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
261: addr = (struct endevice *)ui->ui_addr;
262: addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
263: addr->en_odelay = es->es_delay;
264: addr->en_owc = -((es->es_olen + 1) >> 1);
265: addr->en_ostat = EN_IEN|EN_GO;
266: es->es_oactive = 1;
267: }
268:
269: /*
270: * Ethernet interface transmitter interrupt.
271: * Start another output if more data to send.
272: */
273: enxint(unit)
274: int unit;
275: {
276: register struct uba_device *ui = eninfo[unit];
277: register struct en_softc *es = &en_softc[unit];
278: register struct endevice *addr = (struct endevice *)ui->ui_addr;
279:
280: if (es->es_oactive == 0)
281: return;
282: if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
283: es->es_if.if_oerrors++;
284: endocoll(unit);
285: return;
286: }
287: es->es_if.if_opackets++;
288: es->es_oactive = 0;
289: es->es_delay = 0;
290: es->es_mask = ~0;
291: if (es->es_ifuba.ifu_xtofree) {
292: m_freem(es->es_ifuba.ifu_xtofree);
293: es->es_ifuba.ifu_xtofree = 0;
294: }
295: if (es->es_if.if_snd.ifq_head == 0) {
296: es->es_lastx = 256; /* putatively illegal */
297: return;
298: }
299: enstart(unit);
300: }
301:
302: /*
303: * Collision on ethernet interface. Do exponential
304: * backoff, and retransmit. If have backed off all
305: * the way print warning diagnostic, and drop packet.
306: */
307: encollide(unit)
308: int unit;
309: {
310: struct en_softc *es = &en_softc[unit];
311:
312: es->es_if.if_collisions++;
313: if (es->es_oactive == 0)
314: return;
315: endocoll(unit);
316: }
317:
318: endocoll(unit)
319: int unit;
320: {
321: register struct en_softc *es = &en_softc[unit];
322:
323: /*
324: * Es_mask is a 16 bit number with n low zero bits, with
325: * n the number of backoffs. When es_mask is 0 we have
326: * backed off 16 times, and give up.
327: */
328: if (es->es_mask == 0) {
329: printf("en%d: send error\n", unit);
330: enxint(unit);
331: return;
332: }
333: /*
334: * Another backoff. Restart with delay based on n low bits
335: * of the interval timer.
336: */
337: es->es_mask <<= 1;
338: es->es_delay = mfpr(ICR) &~ es->es_mask;
339: enstart(unit);
340: }
341:
342: #ifdef notdef
343: struct sockproto enproto = { AF_ETHERLINK };
344: struct sockaddr_en endst = { AF_ETHERLINK };
345: struct sockaddr_en ensrc = { AF_ETHERLINK };
346: #endif
347: /*
348: * Ethernet interface receiver interrupt.
349: * If input error just drop packet.
350: * Otherwise purge input buffered data path and examine
351: * packet to determine type. If can't determine length
352: * from type, then have to drop packet. Othewise decapsulate
353: * packet based on type and pass to type specific higher-level
354: * input routine.
355: */
356: enrint(unit)
357: int unit;
358: {
359: register struct en_softc *es = &en_softc[unit];
360: struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
361: register struct en_header *en;
362: struct mbuf *m;
363: int len; short resid;
364: register struct ifqueue *inq;
365: int off;
366:
367: es->es_if.if_ipackets++;
368:
369: /*
370: * Purge BDP; drop if input error indicated.
371: */
372: if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
373: UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
374: if (addr->en_istat&EN_IERROR) {
375: es->es_if.if_ierrors++;
376: goto setup;
377: }
378:
379: /*
380: * Calculate input data length.
381: * Get pointer to ethernet header (in input buffer).
382: * Deal with trailer protocol: if type is PUP trailer
383: * get true type from first 16-bit word past data.
384: * Remember that type was trailer by setting off.
385: */
386: resid = addr->en_iwc;
387: if (resid)
388: resid |= 0176000;
389: len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
390: len -= sizeof (struct en_header);
391: if (len > ENMRU)
392: goto setup; /* sanity */
393: en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
394: en->en_type = ntohs(en->en_type);
395: #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off))))
396: if (en->en_type >= ENTYPE_TRAIL &&
397: en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) {
398: off = (en->en_type - ENTYPE_TRAIL) * 512;
399: if (off > ENMTU)
400: goto setup; /* sanity */
401: en->en_type = ntohs(*endataaddr(en, off, u_short *));
402: resid = ntohs(*(endataaddr(en, off+2, u_short *)));
403: if (off + resid > len)
404: goto setup; /* sanity */
405: len = off + resid;
406: } else
407: off = 0;
408: if (len == 0)
409: goto setup;
410: #ifdef ENF_SWABIPS
411: if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP)
412: enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len);
413: #endif
414: /*
415: * Pull packet off interface. Off is nonzero if packet
416: * has trailing header; if_rubaget will then force this header
417: * information to be at the front, but we still have to drop
418: * the type and length which are at the front of any trailer data.
419: */
420: m = if_rubaget(&es->es_ifuba, len, off);
421: if (m == 0)
422: goto setup;
423: if (off) {
424: m->m_off += 2 * sizeof (u_short);
425: m->m_len -= 2 * sizeof (u_short);
426: }
427: switch (en->en_type) {
428:
429: #ifdef INET
430: case ENTYPE_IP:
431: schednetisr(NETISR_IP);
432: inq = &ipintrq;
433: break;
434: #endif
435: #ifdef PUP
436: case ENTYPE_PUP:
437: rpup_input(m);
438: goto setup;
439: #endif
440: default:
441: #ifdef notdef
442: enproto.sp_protocol = en->en_type;
443: endst.sen_host = en->en_dhost;
444: endst.sen_net = ensrc.sen_net = es->es_if.if_net;
445: ensrc.sen_host = en->en_shost;
446: raw_input(m, &enproto,
447: (struct sockaddr *)&ensrc, (struct sockaddr *)&endst);
448: #else
449: m_freem(m);
450: #endif
451: goto setup;
452: }
453:
454: if (IF_QFULL(inq)) {
455: IF_DROP(inq);
456: m_freem(m);
457: } else
458: IF_ENQUEUE(inq, m);
459:
460: setup:
461: /*
462: * Reset for next packet.
463: */
464: addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
465: addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
466: addr->en_istat = EN_IEN|EN_GO;
467: }
468:
469: /*
470: * Ethernet output routine.
471: * Encapsulate a packet of type family for the local net.
472: * Use trailer local net encapsulation if enough data in first
473: * packet leaves a multiple of 512 bytes of data in remainder.
474: */
475: enoutput(ifp, m0, dst)
476: struct ifnet *ifp;
477: struct mbuf *m0;
478: struct sockaddr *dst;
479: {
480: int type, dest, s, error;
481: register struct mbuf *m = m0;
482: register struct en_header *en;
483: register int off;
484:
485: switch (dst->sa_family) {
486:
487: #ifdef INET
488: case AF_INET:
489: dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
490: if (in_lnaof(*((struct in_addr *)&dest)) >= 0x100) {
491: error = EPERM; /* ??? */
492: goto bad;
493: }
494: dest = (dest >> 24) & 0xff;
495: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
496: /* need per host negotiation */
497: if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
498: if (off > 0 && (off & 0x1ff) == 0 &&
499: m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
500: type = ENTYPE_TRAIL + (off>>9);
501: m->m_off -= 2 * sizeof (u_short);
502: m->m_len += 2 * sizeof (u_short);
503: *mtod(m, u_short *) = htons((u_short)ENTYPE_IP);
504: *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
505: goto gottrailertype;
506: }
507: type = ENTYPE_IP;
508: off = 0;
509: goto gottype;
510: #endif
511: #ifdef PUP
512: case AF_PUP:
513: dest = ((struct sockaddr_pup *)dst)->spup_host;
514: type = ENTYPE_PUP;
515: off = 0;
516: goto gottype;
517: #endif
518:
519: #ifdef notdef
520: case AF_ETHERLINK:
521: goto gotheader;
522: #endif
523:
524: default:
525: printf("en%d: can't handle af%d\n", ifp->if_unit,
526: dst->sa_family);
527: error = EAFNOSUPPORT;
528: goto bad;
529: }
530:
531: gottrailertype:
532: /*
533: * Packet to be sent as trailer: move first packet
534: * (control information) to end of chain.
535: */
536: while (m->m_next)
537: m = m->m_next;
538: m->m_next = m0;
539: m = m0->m_next;
540: m0->m_next = 0;
541: m0 = m;
542:
543: gottype:
544: /*
545: * Add local net header. If no space in first mbuf,
546: * allocate another.
547: */
548: if (m->m_off > MMAXOFF ||
549: MMINOFF + sizeof (struct en_header) > m->m_off) {
550: m = m_get(M_DONTWAIT, MT_HEADER);
551: if (m == 0) {
552: error = ENOBUFS;
553: goto bad;
554: }
555: m->m_next = m0;
556: m->m_off = MMINOFF;
557: m->m_len = sizeof (struct en_header);
558: } else {
559: m->m_off -= sizeof (struct en_header);
560: m->m_len += sizeof (struct en_header);
561: }
562: en = mtod(m, struct en_header *);
563: en->en_shost = ifp->if_host[0];
564: en->en_dhost = dest;
565: en->en_type = htons((u_short)type);
566:
567: gotheader:
568: /*
569: * Queue message on interface, and start output if interface
570: * not yet active.
571: */
572: s = splimp();
573: if (IF_QFULL(&ifp->if_snd)) {
574: IF_DROP(&ifp->if_snd);
575: error = ENOBUFS;
576: goto qfull;
577: }
578: IF_ENQUEUE(&ifp->if_snd, m);
579: if (en_softc[ifp->if_unit].es_oactive == 0)
580: enstart(ifp->if_unit);
581: splx(s);
582: return (0);
583: qfull:
584: m0 = m;
585: splx(s);
586: bad:
587: m_freem(m0);
588: return (error);
589: }
590:
591: /*
592: * Process an ioctl request.
593: */
594: enioctl(ifp, cmd, data)
595: register struct ifnet *ifp;
596: int cmd;
597: caddr_t data;
598: {
599: struct ifreq *ifr = (struct ifreq *)data;
600: int s = splimp(), error = 0;
601:
602: switch (cmd) {
603:
604: case SIOCSIFADDR:
605: if (ifp->if_flags & IFF_RUNNING)
606: if_rtinit(ifp, -1); /* delete previous route */
607: ensetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
608: if (ifp->if_flags & IFF_RUNNING)
609: if_rtinit(ifp, RTF_UP);
610: else
611: eninit(ifp->if_unit);
612: break;
613:
614: default:
615: error = EINVAL;
616: }
617: splx(s);
618: return (error);
619: }
620:
621: ensetaddr(ifp, sin)
622: register struct ifnet *ifp;
623: register struct sockaddr_in *sin;
624: {
625: struct endevice *enaddr;
626:
627: ifp->if_net = in_netof(sin->sin_addr);
628: enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr;
629: ifp->if_host[0] = (~enaddr->en_addr) & 0xff;
630: sin = (struct sockaddr_in *)&ifp->if_addr;
631: sin->sin_family = AF_INET;
632: sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
633: sin = (struct sockaddr_in *)&ifp->if_broadaddr;
634: sin->sin_family = AF_INET;
635: sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
636: ifp->if_flags |= IFF_BROADCAST;
637: }
638:
639: #ifdef ENF_SWABIPS
640: /*
641: * Swab bytes
642: * Jeffrey Mogul, Stanford
643: */
644: enswab(from, to, n)
645: register caddr_t *from, *to;
646: register int n;
647: {
648: register unsigned long temp;
649:
650: n >>= 1; n++;
651: #define STEP temp = *from++,*to++ = *from++,*to++ = temp
652: /* round to multiple of 8 */
653: while ((--n) & 07)
654: STEP;
655: n >>= 3;
656: while (--n >= 0) {
657: STEP; STEP; STEP; STEP;
658: STEP; STEP; STEP; STEP;
659: }
660: }
661: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.