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