|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)if_en.c 7.6 (Berkeley) 6/28/90
21: */
22:
23: #include "en.h"
24: #if NEN > 0
25:
26: /*
27: * Xerox prototype (3 Mb) Ethernet interface driver.
28: */
29: #include "machine/pte.h"
30:
31: #include "param.h"
32: #include "systm.h"
33: #include "mbuf.h"
34: #include "buf.h"
35: #include "protosw.h"
36: #include "socket.h"
37: #include "vmmac.h"
38: #include "errno.h"
39: #include "ioctl.h"
40:
41: #include "../net/if.h"
42: #include "../net/netisr.h"
43: #include "../net/route.h"
44:
45: #ifdef INET
46: #include "../netinet/in.h"
47: #include "../netinet/in_systm.h"
48: #include "../netinet/in_var.h"
49: #include "../netinet/ip.h"
50: #endif
51:
52: #ifdef PUP
53: #include "../netpup/pup.h"
54: #include "../netpup/ether.h"
55: #endif
56:
57: #ifdef NS
58: #include "../netns/ns.h"
59: #include "../netns/ns_if.h"
60: #endif
61:
62: #include "../vax/cpu.h"
63: #include "../vax/mtpr.h"
64: #include "if_en.h"
65: #include "if_enreg.h"
66: #include "if_uba.h"
67: #include "../vaxuba/ubareg.h"
68: #include "../vaxuba/ubavar.h"
69:
70: #define ENMTU (1024+512)
71: #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */
72:
73: int enprobe(), enattach(), enrint(), enxint(), encollide();
74: struct uba_device *eninfo[NEN];
75: u_short enstd[] = { 0 };
76: struct uba_driver endriver =
77: { enprobe, 0, enattach, 0, enstd, "en", eninfo };
78: #define ENUNIT(x) minor(x)
79:
80: int eninit(),oldenoutput(),enreset(),enioctl(), enstart();
81:
82: #ifdef notdef
83: /*
84: * If you need to byte swap IP's in the system, define
85: * this and do a SIOCSIFFLAGS at boot time.
86: */
87: #define ENF_SWABIPS 0x1000
88: #endif
89:
90: /*
91: * Ethernet software status per interface.
92: *
93: * Each interface is referenced by a network interface structure,
94: * es_if, which the routing code uses to locate the interface.
95: * This structure contains the output queue for the interface, its address, ...
96: * We also have, for each interface, a UBA interface structure, which
97: * contains information about the UNIBUS resources held by the interface:
98: * map registers, buffered data paths, etc. Information is cached in this
99: * structure for use by the if_uba.c routines in running the interface
100: * efficiently.
101: */
102: struct en_softc {
103: struct ifnet es_if; /* network-visible interface */
104: struct ifuba es_ifuba; /* UNIBUS resources */
105: short es_host; /* hardware host number */
106: short es_delay; /* current output delay */
107: short es_mask; /* mask for current output delay */
108: short es_lastx; /* host last transmitted to */
109: short es_oactive; /* is output active? */
110: short es_olen; /* length of last output */
111: short es_nsactive; /* is interface enabled for ns? */
112: } en_softc[NEN];
113:
114: /*
115: * Do output DMA to determine interface presence and
116: * interrupt vector. DMA is too short to disturb other hosts.
117: */
118: enprobe(reg)
119: caddr_t reg;
120: {
121: register int br, cvec; /* r11, r10 value-result */
122: register struct endevice *addr = (struct endevice *)reg;
123:
124: #ifdef lint
125: br = 0; cvec = br; br = cvec;
126: enrint(0); enxint(0); encollide(0);
127: #endif
128: addr->en_istat = 0;
129: addr->en_owc = -1;
130: addr->en_oba = 0;
131: addr->en_ostat = EN_IEN|EN_GO;
132: DELAY(100000);
133: addr->en_ostat = 0;
134: return (1);
135: }
136:
137: /*
138: * Interface exists: make available by filling in network interface
139: * record. System will initialize the interface when it is ready
140: * to accept packets.
141: */
142: enattach(ui)
143: struct uba_device *ui;
144: {
145: register struct en_softc *es = &en_softc[ui->ui_unit];
146:
147: es->es_if.if_unit = ui->ui_unit;
148: es->es_if.if_name = "en";
149: es->es_if.if_mtu = ENMTU;
150: es->es_if.if_flags = IFF_BROADCAST;
151: es->es_if.if_init = eninit;
152: es->es_if.if_output = oldenoutput;
153: es->es_if.if_start = enstart;
154: es->es_if.if_ioctl = enioctl;
155: es->es_if.if_reset = enreset;
156: es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
157: #if defined(VAX750)
158: /* don't chew up 750 bdp's */
159: if (cpu == VAX_750 && ui->ui_unit > 0)
160: es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP;
161: #endif
162: if_attach(&es->es_if);
163: }
164:
165: /*
166: * Reset of interface after UNIBUS reset.
167: * If interface is on specified uba, reset its state.
168: */
169: enreset(unit, uban)
170: int unit, uban;
171: {
172: register struct uba_device *ui;
173:
174: if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
175: ui->ui_ubanum != uban)
176: return;
177: printf(" en%d", unit);
178: eninit(unit);
179: }
180:
181: /*
182: * Initialization of interface; clear recorded pending
183: * operations, and reinitialize UNIBUS usage.
184: */
185: eninit(unit)
186: int unit;
187: {
188: register struct en_softc *es = &en_softc[unit];
189: register struct uba_device *ui = eninfo[unit];
190: register struct endevice *addr;
191: int s;
192:
193: if (es->es_if.if_addrlist == (struct ifaddr *)0)
194: return;
195: if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
196: sizeof (struct en_header), (int)btoc(ENMRU)) == 0) {
197: printf("en%d: can't initialize\n", unit);
198: es->es_if.if_flags &= ~IFF_UP;
199: return;
200: }
201: addr = (struct endevice *)ui->ui_addr;
202: addr->en_istat = addr->en_ostat = 0;
203:
204: /*
205: * Hang a receive and start any
206: * pending writes by faking a transmit complete.
207: */
208: s = splimp();
209: addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
210: addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
211: addr->en_istat = EN_IEN|EN_GO;
212: es->es_oactive = 1;
213: es->es_if.if_flags |= IFF_RUNNING;
214: enxint(unit);
215: splx(s);
216: }
217:
218: int enalldelay = 0;
219: int enlastdel = 50;
220: int enlastmask = (~0) << 5;
221:
222: /*
223: * Start or restart output on interface.
224: * If interface is already active, then this is a retransmit
225: * after a collision, and just restuff registers and delay.
226: * If interface is not already active, get another datagram
227: * to send off of the interface queue, and map it to the interface
228: * before starting the output.
229: */
230: enstart(dev)
231: dev_t dev;
232: {
233: int unit = ENUNIT(dev);
234: struct uba_device *ui = eninfo[unit];
235: register struct en_softc *es = &en_softc[unit];
236: register struct endevice *addr;
237: register struct en_header *en;
238: struct mbuf *m;
239: int dest;
240:
241: if (es->es_oactive)
242: goto restart;
243:
244: /*
245: * Not already active: dequeue another request
246: * and map it to the UNIBUS. If no more requests,
247: * just return.
248: */
249: IF_DEQUEUE(&es->es_if.if_snd, m);
250: if (m == 0) {
251: es->es_oactive = 0;
252: return;
253: }
254: en = mtod(m, struct en_header *);
255: dest = en->en_dhost;
256: en->en_shost = es->es_host;
257: es->es_olen = if_wubaput(&es->es_ifuba, m);
258: #ifdef ENF_SWABIPS
259: /*
260: * The Xerox interface does word at a time DMA, so
261: * someone must do byte swapping of user data if high
262: * and low ender machines are to communicate. It doesn't
263: * belong here, but certain people depend on it, so...
264: *
265: * Should swab everybody, but this is a kludge anyway.
266: */
267: if (es->es_if.if_flags & ENF_SWABIPS) {
268: en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr;
269: if (en->en_type == ENTYPE_IP)
270: enswab((caddr_t)(en + 1), (caddr_t)(en + 1),
271: es->es_olen - sizeof (struct en_header) + 1);
272: }
273: #endif
274:
275: /*
276: * Ethernet cannot take back-to-back packets (no
277: * buffering in interface. To help avoid overrunning
278: * receivers, enforce a small delay (about 1ms) in interface:
279: * * between all packets when enalldelay
280: * * whenever last packet was broadcast
281: * * whenever this packet is to same host as last packet
282: */
283: if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
284: es->es_delay = enlastdel;
285: es->es_mask = enlastmask;
286: }
287: es->es_lastx = dest;
288:
289: restart:
290: /*
291: * Have request mapped to UNIBUS for transmission.
292: * Purge any stale data from this BDP, and start the otput.
293: */
294: if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
295: UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
296: addr = (struct endevice *)ui->ui_addr;
297: addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
298: addr->en_odelay = es->es_delay;
299: addr->en_owc = -((es->es_olen + 1) >> 1);
300: addr->en_ostat = EN_IEN|EN_GO;
301: es->es_oactive = 1;
302: }
303:
304: /*
305: * Ethernet interface transmitter interrupt.
306: * Start another output if more data to send.
307: */
308: enxint(unit)
309: int unit;
310: {
311: register struct uba_device *ui = eninfo[unit];
312: register struct en_softc *es = &en_softc[unit];
313: register struct endevice *addr = (struct endevice *)ui->ui_addr;
314:
315: if (es->es_oactive == 0)
316: return;
317: if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
318: es->es_if.if_oerrors++;
319: endocoll(unit);
320: return;
321: }
322: es->es_if.if_opackets++;
323: es->es_oactive = 0;
324: es->es_delay = 0;
325: es->es_mask = ~0;
326: if (es->es_ifuba.ifu_xtofree) {
327: m_freem(es->es_ifuba.ifu_xtofree);
328: es->es_ifuba.ifu_xtofree = 0;
329: }
330: if (es->es_if.if_snd.ifq_head == 0) {
331: es->es_lastx = 256; /* putatively illegal */
332: return;
333: }
334: enstart(unit);
335: }
336:
337: /*
338: * Collision on ethernet interface. Do exponential
339: * backoff, and retransmit. If have backed off all
340: * the way print warning diagnostic, and drop packet.
341: */
342: encollide(unit)
343: int unit;
344: {
345: struct en_softc *es = &en_softc[unit];
346:
347: es->es_if.if_collisions++;
348: if (es->es_oactive == 0)
349: return;
350: endocoll(unit);
351: }
352:
353: endocoll(unit)
354: int unit;
355: {
356: register struct en_softc *es = &en_softc[unit];
357:
358: /*
359: * Es_mask is a 16 bit number with n low zero bits, with
360: * n the number of backoffs. When es_mask is 0 we have
361: * backed off 16 times, and give up.
362: */
363: if (es->es_mask == 0) {
364: printf("en%d: send error\n", unit);
365: enxint(unit);
366: return;
367: }
368: /*
369: * Another backoff. Restart with delay based on n low bits
370: * of the interval timer.
371: */
372: es->es_mask <<= 1;
373: es->es_delay = mfpr(ICR) &~ es->es_mask;
374: enstart(unit);
375: }
376:
377: #ifdef notdef
378: struct sockproto enproto = { AF_ETHERLINK };
379: struct sockaddr_en endst = { sizeof(endst), AF_ETHERLINK };
380: struct sockaddr_en ensrc = { sizeof(ensrc), AF_ETHERLINK };
381: #endif
382: /*
383: * Ethernet interface receiver interrupt.
384: * If input error just drop packet.
385: * Otherwise purge input buffered data path and examine
386: * packet to determine type. If can't determine length
387: * from type, then have to drop packet. Othewise decapsulate
388: * packet based on type and pass to type specific higher-level
389: * input routine.
390: */
391: enrint(unit)
392: int unit;
393: {
394: register struct en_softc *es = &en_softc[unit];
395: struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
396: register struct en_header *en;
397: struct mbuf *m;
398: int len; short resid;
399: register struct ifqueue *inq;
400: int off, s;
401:
402: es->es_if.if_ipackets++;
403:
404: /*
405: * Purge BDP; drop if input error indicated.
406: */
407: if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
408: UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
409: if (addr->en_istat&EN_IERROR) {
410: es->es_if.if_ierrors++;
411: goto setup;
412: }
413:
414: /*
415: * Calculate input data length.
416: * Get pointer to ethernet header (in input buffer).
417: * Deal with trailer protocol: if type is PUP trailer
418: * get true type from first 16-bit word past data.
419: * Remember that type was trailer by setting off.
420: */
421: resid = addr->en_iwc;
422: if (resid)
423: resid |= 0176000;
424: len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
425: len -= sizeof (struct en_header);
426: if (len > ENMRU)
427: goto setup; /* sanity */
428: en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
429: en->en_type = ntohs(en->en_type);
430: #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off))))
431: if (en->en_type >= ENTYPE_TRAIL &&
432: en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) {
433: off = (en->en_type - ENTYPE_TRAIL) * 512;
434: if (off > ENMTU)
435: goto setup; /* sanity */
436: en->en_type = ntohs(*endataaddr(en, off, u_short *));
437: resid = ntohs(*(endataaddr(en, off+2, u_short *)));
438: if (off + resid > len)
439: goto setup; /* sanity */
440: len = off + resid;
441: } else
442: off = 0;
443: if (len == 0)
444: goto setup;
445: #ifdef ENF_SWABIPS
446: if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP)
447: enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len);
448: #endif
449: /*
450: * Pull packet off interface. Off is nonzero if packet
451: * has trailing header; if_rubaget will then force this header
452: * information to be at the front, but we still have to drop
453: * the type and length which are at the front of any trailer data.
454: */
455: m = if_rubaget(&es->es_ifuba, len, off, &es->es_if);
456: if (m == 0)
457: goto setup;
458: switch (en->en_type) {
459:
460: #ifdef INET
461: case ENTYPE_IP:
462: schednetisr(NETISR_IP);
463: inq = &ipintrq;
464: break;
465: #endif
466: #ifdef PUP
467: case ENTYPE_PUP:
468: rpup_input(m);
469: goto setup;
470: #endif
471: #ifdef NS
472: case ETHERTYPE_NS:
473: if (es->es_nsactive) {
474: schednetisr(NETISR_NS);
475: inq = &nsintrq;
476: } else {
477: m_freem(m);
478: goto setup;
479: }
480: break;
481: #endif
482:
483: default:
484: #ifdef notdef
485: enproto.sp_protocol = en->en_type;
486: endst.sen_host = en->en_dhost;
487: endst.sen_net = ensrc.sen_net = es->es_if.if_net;
488: ensrc.sen_host = en->en_shost;
489: raw_input(m, &enproto,
490: (struct sockaddr *)&ensrc, (struct sockaddr *)&endst);
491: #else
492: m_freem(m);
493: #endif
494: goto setup;
495: }
496:
497: s = splimp();
498: if (IF_QFULL(inq)) {
499: IF_DROP(inq);
500: m_freem(m);
501: } else
502: IF_ENQUEUE(inq, m);
503: splx(s);
504:
505: setup:
506: /*
507: * Reset for next packet.
508: */
509: addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
510: addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
511: addr->en_istat = EN_IEN|EN_GO;
512: }
513:
514: /*
515: * Ethernet output routine.
516: * Encapsulate a packet of type family for the local net.
517: * Use trailer local net encapsulation if enough data in first
518: * packet leaves a multiple of 512 bytes of data in remainder.
519: */
520: oldenoutput(ifp, m0, dst)
521: struct ifnet *ifp;
522: struct mbuf *m0;
523: struct sockaddr *dst;
524: {
525: int type, dest, s, error;
526: register struct mbuf *m = m0;
527: register struct en_header *en;
528: register int off;
529:
530: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
531: error = ENETDOWN;
532: goto bad;
533: }
534: switch (dst->sa_family) {
535:
536: #ifdef INET
537: case AF_INET:
538: {
539: struct in_addr in;
540:
541: in = ((struct sockaddr_in *)dst)->sin_addr;
542: if (in_broadcast(in))
543: dest = EN_BROADCAST;
544: else
545: dest = in_lnaof(in);
546: }
547: if (dest >= 0x100) {
548: error = EPERM; /* ??? */
549: goto bad;
550: }
551: off = m->m_pkthdr.len - m->m_len;
552: /* need per host negotiation */
553: if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
554: if (off > 0 && (off & 0x1ff) == 0 &&
555: (m->m_flags & M_EXT) == 0 &&
556: m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
557: type = ENTYPE_TRAIL + (off>>9);
558: m->m_data -= 2 * sizeof (u_short);
559: m->m_len += 2 * sizeof (u_short);
560: *mtod(m, u_short *) = htons((u_short)ENTYPE_IP);
561: *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
562: goto gottrailertype;
563: }
564: type = ENTYPE_IP;
565: off = 0;
566: goto gottype;
567: #endif
568: #ifdef NS
569: case AF_NS:
570: {
571: u_char *up;
572:
573: type = ETHERTYPE_NS;
574: up = ((struct sockaddr_ns *)dst)->sns_addr.x_host.c_host;
575: if (*up & 1)
576: dest = EN_BROADCAST;
577: else
578: dest = up[5];
579:
580: off = 0;
581: goto gottype;
582: }
583: #endif
584: #ifdef PUP
585: case AF_PUP:
586: dest = ((struct sockaddr_pup *)dst)->spup_host;
587: type = ENTYPE_PUP;
588: off = 0;
589: goto gottype;
590: #endif
591:
592: #ifdef notdef
593: case AF_ETHERLINK:
594: goto gotheader;
595: #endif
596:
597: default:
598: printf("en%d: can't handle af%d\n", ifp->if_unit,
599: dst->sa_family);
600: error = EAFNOSUPPORT;
601: goto bad;
602: }
603:
604: gottrailertype:
605: /*
606: * Packet to be sent as trailer: move first packet
607: * (control information) to end of chain.
608: */
609: while (m->m_next)
610: m = m->m_next;
611: m->m_next = m0;
612: m = m0->m_next;
613: m0->m_next = 0;
614: m0 = m;
615:
616: gottype:
617: /*
618: * Add local net header. If no space in first mbuf,
619: * allocate another.
620: */
621: M_PREPEND(m, sizeof (struct en_header), M_DONTWAIT);
622: if (m == NULL)
623: return (ENOBUFS);
624: en = mtod(m, struct en_header *);
625: /* add en_shost later */
626: en->en_dhost = dest;
627: en->en_type = htons((u_short)type);
628:
629: #ifdef notdef
630: gotheader:
631: #endif
632: /*
633: * Queue message on interface, and start output if interface
634: * not yet active.
635: */
636: s = splimp();
637: if (IF_QFULL(&ifp->if_snd)) {
638: IF_DROP(&ifp->if_snd);
639: error = ENOBUFS;
640: goto qfull;
641: }
642: IF_ENQUEUE(&ifp->if_snd, m);
643: if (en_softc[ifp->if_unit].es_oactive == 0)
644: enstart(ifp->if_unit);
645: splx(s);
646: return (0);
647: qfull:
648: m0 = m;
649: splx(s);
650: bad:
651: m_freem(m0);
652: return (error);
653: }
654:
655: /*
656: * Process an ioctl request.
657: */
658: enioctl(ifp, cmd, data)
659: register struct ifnet *ifp;
660: int cmd;
661: caddr_t data;
662: {
663: register struct en_softc *es = ((struct en_softc *)ifp);
664: struct ifaddr *ifa = (struct ifaddr *) data;
665: int s = splimp(), error = 0;
666: struct endevice *enaddr;
667:
668: switch (cmd) {
669:
670: case SIOCSIFADDR:
671: enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr;
672: es->es_host = (~enaddr->en_addr) & 0xff;
673: /*
674: * Attempt to check agreement of protocol address
675: * and board address.
676: */
677: switch (ifa->ifa_addr->sa_family) {
678: case AF_INET:
679: if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host)
680: return (EADDRNOTAVAIL);
681: break;
682: #ifdef NS
683: case AF_NS:
684: if (IA_SNS(ifa)->sns_addr.x_host.c_host[5]
685: != es->es_host)
686: return (EADDRNOTAVAIL);
687: es->es_nsactive = 1;
688: break;
689: #endif
690: }
691: ifp->if_flags |= IFF_UP;
692: if ((ifp->if_flags & IFF_RUNNING) == 0)
693: eninit(ifp->if_unit);
694: break;
695:
696: default:
697: error = EINVAL;
698: break;
699: }
700: splx(s);
701: return (error);
702: }
703:
704: #ifdef ENF_SWABIPS
705: /*
706: * Swab bytes
707: * Jeffrey Mogul, Stanford
708: */
709: enswab(from, to, n)
710: register unsigned char *from, *to;
711: register int n;
712: {
713: register unsigned long temp;
714:
715: if ((n <= 0) || (n > 0xFFFF)) {
716: printf("enswab: bad len %d\n", n);
717: return;
718: }
719:
720: n >>= 1; n++;
721: #define STEP {temp = *from++;*to++ = *from++;*to++ = temp;}
722: /* round to multiple of 8 */
723: while ((--n) & 07)
724: STEP;
725: n >>= 3;
726: while (--n >= 0) {
727: STEP; STEP; STEP; STEP;
728: STEP; STEP; STEP; STEP;
729: }
730: }
731: #endif
732: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.