1*13458Ssam /* if_en.c 4.82 83/06/30 */ 24686Swnj 34686Swnj #include "en.h" 45105Swnj 54686Swnj /* 65105Swnj * Xerox prototype (3 Mb) Ethernet interface driver. 74686Swnj */ 89796Ssam #include "../machine/pte.h" 94686Swnj 104686Swnj #include "../h/param.h" 114686Swnj #include "../h/systm.h" 124686Swnj #include "../h/mbuf.h" 134686Swnj #include "../h/buf.h" 145083Swnj #include "../h/protosw.h" 155083Swnj #include "../h/socket.h" 165083Swnj #include "../h/vmmac.h" 1713054Ssam #include "../h/errno.h" 1813054Ssam #include "../h/ioctl.h" 198462Sroot 208462Sroot #include "../net/if.h" 218462Sroot #include "../net/netisr.h" 228462Sroot #include "../net/route.h" 238418Swnj #include "../netinet/in.h" 248418Swnj #include "../netinet/in_systm.h" 258418Swnj #include "../netinet/ip.h" 268418Swnj #include "../netinet/ip_var.h" 278418Swnj #include "../netpup/pup.h" 28*13458Ssam #include "../netpup/ether.h" 294686Swnj 308462Sroot #include "../vax/cpu.h" 318462Sroot #include "../vax/mtpr.h" 328462Sroot #include "../vaxif/if_en.h" 338462Sroot #include "../vaxif/if_enreg.h" 348462Sroot #include "../vaxif/if_uba.h" 358462Sroot #include "../vaxuba/ubareg.h" 368462Sroot #include "../vaxuba/ubavar.h" 378462Sroot 385213Swnj #define ENMTU (1024+512) 396925Swnj #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */ 405083Swnj 414686Swnj int enprobe(), enattach(), enrint(), enxint(), encollide(); 424686Swnj struct uba_device *eninfo[NEN]; 434686Swnj u_short enstd[] = { 0 }; 444686Swnj struct uba_driver endriver = 455171Swnj { enprobe, 0, enattach, 0, enstd, "en", eninfo }; 464686Swnj #define ENUNIT(x) minor(x) 474686Swnj 4813054Ssam int eninit(),enoutput(),enreset(),enioctl(); 495105Swnj 5013293Ssam #ifdef notdef 515105Swnj /* 5213293Ssam * If you need to byte swap IP's in the system, define 5313293Ssam * this and do a SIOCSIFFLAGS at boot time. 5413293Ssam */ 5513293Ssam #define ENF_SWABIPS 0x100 5613293Ssam #endif 5713293Ssam 5813293Ssam /* 595105Swnj * Ethernet software status per interface. 605105Swnj * 615105Swnj * Each interface is referenced by a network interface structure, 625105Swnj * es_if, which the routing code uses to locate the interface. 635105Swnj * This structure contains the output queue for the interface, its address, ... 645105Swnj * We also have, for each interface, a UBA interface structure, which 655105Swnj * contains information about the UNIBUS resources held by the interface: 665105Swnj * map registers, buffered data paths, etc. Information is cached in this 675105Swnj * structure for use by the if_uba.c routines in running the interface 685105Swnj * efficiently. 695105Swnj */ 705083Swnj struct en_softc { 715105Swnj struct ifnet es_if; /* network-visible interface */ 725105Swnj struct ifuba es_ifuba; /* UNIBUS resources */ 735105Swnj short es_delay; /* current output delay */ 745105Swnj short es_mask; /* mask for current output delay */ 756471Sroot short es_lastx; /* host last transmitted to */ 765105Swnj short es_oactive; /* is output active? */ 775105Swnj short es_olen; /* length of last output */ 785083Swnj } en_softc[NEN]; 794686Swnj 805105Swnj /* 815105Swnj * Do output DMA to determine interface presence and 825105Swnj * interrupt vector. DMA is too short to disturb other hosts. 835105Swnj */ 844686Swnj enprobe(reg) 854686Swnj caddr_t reg; 864686Swnj { 875171Swnj register int br, cvec; /* r11, r10 value-result */ 884686Swnj register struct endevice *addr = (struct endevice *)reg; 894686Swnj 904686Swnj #ifdef lint 914686Swnj br = 0; cvec = br; br = cvec; 924922Swnj enrint(0); enxint(0); encollide(0); 934686Swnj #endif 944686Swnj addr->en_istat = 0; 954686Swnj addr->en_owc = -1; 964686Swnj addr->en_oba = 0; 974771Swnj addr->en_ostat = EN_IEN|EN_GO; 984686Swnj DELAY(100000); 994686Swnj addr->en_ostat = 0; 1004686Swnj return (1); 1014686Swnj } 1024686Swnj 1035105Swnj /* 1045105Swnj * Interface exists: make available by filling in network interface 1055105Swnj * record. System will initialize the interface when it is ready 1065105Swnj * to accept packets. 1075105Swnj */ 1084686Swnj enattach(ui) 1094686Swnj struct uba_device *ui; 1104686Swnj { 1115105Swnj register struct en_softc *es = &en_softc[ui->ui_unit]; 1124688Swnj 1135105Swnj es->es_if.if_unit = ui->ui_unit; 1145171Swnj es->es_if.if_name = "en"; 1155105Swnj es->es_if.if_mtu = ENMTU; 1165171Swnj es->es_if.if_init = eninit; 1175105Swnj es->es_if.if_output = enoutput; 11813054Ssam es->es_if.if_ioctl = enioctl; 1198978Sroot es->es_if.if_reset = enreset; 1206554Ssam es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT; 1219271Ssam #if defined(VAX750) 1229271Ssam /* don't chew up 750 bdp's */ 1239271Ssam if (cpu == VAX_750 && ui->ui_unit > 0) 1249271Ssam es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP; 1259271Ssam #endif 1265160Swnj if_attach(&es->es_if); 1274686Swnj } 1284686Swnj 1295105Swnj /* 1305105Swnj * Reset of interface after UNIBUS reset. 1315105Swnj * If interface is on specified uba, reset its state. 1325105Swnj */ 1335105Swnj enreset(unit, uban) 1345105Swnj int unit, uban; 1355105Swnj { 1365105Swnj register struct uba_device *ui; 1375105Swnj 1385171Swnj if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || 1395171Swnj ui->ui_ubanum != uban) 1405105Swnj return; 1415171Swnj printf(" en%d", unit); 1425105Swnj eninit(unit); 1435105Swnj } 1445105Swnj 1455105Swnj /* 1465105Swnj * Initialization of interface; clear recorded pending 1475105Swnj * operations, and reinitialize UNIBUS usage. 1485105Swnj */ 1494688Swnj eninit(unit) 1504686Swnj int unit; 1515083Swnj { 1525171Swnj register struct en_softc *es = &en_softc[unit]; 1535171Swnj register struct uba_device *ui = eninfo[unit]; 1544686Swnj register struct endevice *addr; 15512349Ssam struct sockaddr_in *sin = (struct sockaddr_in *)&es->es_if.if_addr; 15613054Ssam int s; 1574686Swnj 15813054Ssam if (in_netof(sin->sin_addr) == 0) 15912349Ssam return; 1605105Swnj if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 1616925Swnj sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 1625171Swnj printf("en%d: can't initialize\n", unit); 1636335Ssam es->es_if.if_flags &= ~IFF_UP; 1645083Swnj return; 1654686Swnj } 1664686Swnj addr = (struct endevice *)ui->ui_addr; 1675083Swnj addr->en_istat = addr->en_ostat = 0; 1684686Swnj 1695105Swnj /* 1705171Swnj * Hang a receive and start any 1715171Swnj * pending writes by faking a transmit complete. 1725105Swnj */ 1735105Swnj s = splimp(); 1745171Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 1756925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 1765171Swnj addr->en_istat = EN_IEN|EN_GO; 1775171Swnj es->es_oactive = 1; 17813054Ssam es->es_if.if_flags |= IFF_UP|IFF_RUNNING; 1795105Swnj enxint(unit); 1805105Swnj splx(s); 1817151Swnj if_rtinit(&es->es_if, RTF_UP); 1824686Swnj } 1834686Swnj 1846471Sroot int enalldelay = 0; 1856951Swnj int enlastdel = 50; 1866471Sroot int enlastmask = (~0) << 5; 1875083Swnj 1885105Swnj /* 1895105Swnj * Start or restart output on interface. 1905105Swnj * If interface is already active, then this is a retransmit 1915105Swnj * after a collision, and just restuff registers and delay. 1925105Swnj * If interface is not already active, get another datagram 1935105Swnj * to send off of the interface queue, and map it to the interface 1945105Swnj * before starting the output. 1955105Swnj */ 1964688Swnj enstart(dev) 1974686Swnj dev_t dev; 1984686Swnj { 1995171Swnj int unit = ENUNIT(dev); 2005171Swnj struct uba_device *ui = eninfo[unit]; 2015171Swnj register struct en_softc *es = &en_softc[unit]; 2025083Swnj register struct endevice *addr; 2035083Swnj struct mbuf *m; 2045083Swnj int dest; 2054686Swnj 2065083Swnj if (es->es_oactive) 2075083Swnj goto restart; 2085105Swnj 2095105Swnj /* 2105105Swnj * Not already active: dequeue another request 2115105Swnj * and map it to the UNIBUS. If no more requests, 2125105Swnj * just return. 2135105Swnj */ 2145105Swnj IF_DEQUEUE(&es->es_if.if_snd, m); 2155083Swnj if (m == 0) { 2165083Swnj es->es_oactive = 0; 2174686Swnj return; 2184686Swnj } 2195213Swnj dest = mtod(m, struct en_header *)->en_dhost; 2205105Swnj es->es_olen = if_wubaput(&es->es_ifuba, m); 22113293Ssam #ifdef ENF_SWABIPS 22213293Ssam /* 22313293Ssam * The Xerox interface does word at a time DMA, so 22413293Ssam * someone must do byte swapping of user data if high 22513293Ssam * and low ender machines are to communicate. It doesn't 22613293Ssam * belong here, but certain people depend on it, so... 22713293Ssam * 22813293Ssam * Should swab everybody, but this is a kludge anyway. 22913293Ssam */ 23013293Ssam if (es->es_if.if_flags & ENF_SWABIPS) { 23113293Ssam register struct en_header *en; 2325105Swnj 23313293Ssam en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr; 23413293Ssam if (en->en_type == ENTYPE_IP) 23513293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), 23613293Ssam es->es_olen - sizeof (struct en_header) + 1); 23713293Ssam } 23813293Ssam #endif 23913293Ssam 2405105Swnj /* 2415105Swnj * Ethernet cannot take back-to-back packets (no 2426471Sroot * buffering in interface. To help avoid overrunning 2436471Sroot * receivers, enforce a small delay (about 1ms) in interface: 2446471Sroot * * between all packets when enalldelay 2456471Sroot * * whenever last packet was broadcast 2466471Sroot * * whenever this packet is to same host as last packet 2475105Swnj */ 2486471Sroot if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 2495083Swnj es->es_delay = enlastdel; 2506471Sroot es->es_mask = enlastmask; 2516471Sroot } 2526471Sroot es->es_lastx = dest; 2535105Swnj 2545083Swnj restart: 2555105Swnj /* 2565105Swnj * Have request mapped to UNIBUS for transmission. 2575105Swnj * Purge any stale data from this BDP, and start the otput. 2585105Swnj */ 2596335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 2606335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 2614686Swnj addr = (struct endevice *)ui->ui_addr; 2625160Swnj addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 2635083Swnj addr->en_odelay = es->es_delay; 2645083Swnj addr->en_owc = -((es->es_olen + 1) >> 1); 2654771Swnj addr->en_ostat = EN_IEN|EN_GO; 2665083Swnj es->es_oactive = 1; 2674686Swnj } 2684686Swnj 2695105Swnj /* 2705105Swnj * Ethernet interface transmitter interrupt. 2715105Swnj * Start another output if more data to send. 2725105Swnj */ 2734686Swnj enxint(unit) 2744686Swnj int unit; 2754686Swnj { 2765171Swnj register struct uba_device *ui = eninfo[unit]; 2775171Swnj register struct en_softc *es = &en_softc[unit]; 2786242Sroot register struct endevice *addr = (struct endevice *)ui->ui_addr; 2794686Swnj 2805083Swnj if (es->es_oactive == 0) 2815083Swnj return; 2826242Sroot if (es->es_mask && (addr->en_ostat&EN_OERROR)) { 2836242Sroot es->es_if.if_oerrors++; 2846242Sroot endocoll(unit); 2856242Sroot return; 2866242Sroot } 2875171Swnj es->es_if.if_opackets++; 2885083Swnj es->es_oactive = 0; 2895083Swnj es->es_delay = 0; 2905083Swnj es->es_mask = ~0; 2915696Sroot if (es->es_ifuba.ifu_xtofree) { 2925696Sroot m_freem(es->es_ifuba.ifu_xtofree); 2935696Sroot es->es_ifuba.ifu_xtofree = 0; 2945696Sroot } 2955105Swnj if (es->es_if.if_snd.ifq_head == 0) { 2966471Sroot es->es_lastx = 256; /* putatively illegal */ 2974686Swnj return; 2984686Swnj } 2995083Swnj enstart(unit); 3004686Swnj } 3014686Swnj 3025105Swnj /* 3035105Swnj * Collision on ethernet interface. Do exponential 3045105Swnj * backoff, and retransmit. If have backed off all 3056335Ssam * the way print warning diagnostic, and drop packet. 3065105Swnj */ 3074686Swnj encollide(unit) 3084686Swnj int unit; 3094686Swnj { 3106242Sroot struct en_softc *es = &en_softc[unit]; 3114686Swnj 3125105Swnj es->es_if.if_collisions++; 3135083Swnj if (es->es_oactive == 0) 3144686Swnj return; 3156242Sroot endocoll(unit); 3166242Sroot } 3176242Sroot 3186242Sroot endocoll(unit) 3196242Sroot int unit; 3206242Sroot { 3216242Sroot register struct en_softc *es = &en_softc[unit]; 3226242Sroot 3235171Swnj /* 3245171Swnj * Es_mask is a 16 bit number with n low zero bits, with 3255171Swnj * n the number of backoffs. When es_mask is 0 we have 3265171Swnj * backed off 16 times, and give up. 3275171Swnj */ 3285083Swnj if (es->es_mask == 0) { 3295213Swnj printf("en%d: send error\n", unit); 3305083Swnj enxint(unit); 3315171Swnj return; 3324686Swnj } 3335171Swnj /* 3345171Swnj * Another backoff. Restart with delay based on n low bits 3355171Swnj * of the interval timer. 3365171Swnj */ 3375171Swnj es->es_mask <<= 1; 3385171Swnj es->es_delay = mfpr(ICR) &~ es->es_mask; 3395171Swnj enstart(unit); 3404686Swnj } 3414686Swnj 342*13458Ssam #ifdef notdef 343*13458Ssam struct sockproto enproto = { AF_ETHERLINK }; 344*13458Ssam struct sockaddr_en endst = { AF_ETHERLINK }; 345*13458Ssam struct sockaddr_en ensrc = { AF_ETHERLINK }; 346*13458Ssam #endif 3475105Swnj /* 3485105Swnj * Ethernet interface receiver interrupt. 3495105Swnj * If input error just drop packet. 3505105Swnj * Otherwise purge input buffered data path and examine 3515105Swnj * packet to determine type. If can't determine length 3525105Swnj * from type, then have to drop packet. Othewise decapsulate 3535105Swnj * packet based on type and pass to type specific higher-level 3545105Swnj * input routine. 3555105Swnj */ 3564686Swnj enrint(unit) 3574686Swnj int unit; 3584686Swnj { 3595171Swnj register struct en_softc *es = &en_softc[unit]; 3605171Swnj struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; 3615171Swnj register struct en_header *en; 3625083Swnj struct mbuf *m; 3638603Sroot int len; short resid; 3645171Swnj register struct ifqueue *inq; 3655083Swnj int off; 3664686Swnj 3675171Swnj es->es_if.if_ipackets++; 3685105Swnj 3695105Swnj /* 3705171Swnj * Purge BDP; drop if input error indicated. 3715105Swnj */ 3726335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 3736335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 3744771Swnj if (addr->en_istat&EN_IERROR) { 3755105Swnj es->es_if.if_ierrors++; 3765083Swnj goto setup; 3774686Swnj } 3785105Swnj 3795105Swnj /* 3806471Sroot * Calculate input data length. 3815105Swnj * Get pointer to ethernet header (in input buffer). 3825105Swnj * Deal with trailer protocol: if type is PUP trailer 3835105Swnj * get true type from first 16-bit word past data. 3845105Swnj * Remember that type was trailer by setting off. 3855105Swnj */ 3866471Sroot resid = addr->en_iwc; 3876471Sroot if (resid) 3886471Sroot resid |= 0176000; 3896925Swnj len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1; 3906471Sroot len -= sizeof (struct en_header); 3916925Swnj if (len > ENMRU) 3926471Sroot goto setup; /* sanity */ 3935105Swnj en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 39412352Ssam en->en_type = ntohs(en->en_type); 3955083Swnj #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 39612352Ssam if (en->en_type >= ENTYPE_TRAIL && 39712352Ssam en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) { 39812352Ssam off = (en->en_type - ENTYPE_TRAIL) * 512; 3996925Swnj if (off > ENMTU) 4005171Swnj goto setup; /* sanity */ 40112352Ssam en->en_type = ntohs(*endataaddr(en, off, u_short *)); 40212352Ssam resid = ntohs(*(endataaddr(en, off+2, u_short *))); 4036471Sroot if (off + resid > len) 4046471Sroot goto setup; /* sanity */ 4056471Sroot len = off + resid; 4065083Swnj } else 4075083Swnj off = 0; 4085083Swnj if (len == 0) 4095083Swnj goto setup; 41013293Ssam #ifdef ENF_SWABIPS 41113293Ssam if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP) 41213293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len); 41313293Ssam #endif 4145105Swnj /* 4155105Swnj * Pull packet off interface. Off is nonzero if packet 4165105Swnj * has trailing header; if_rubaget will then force this header 4175105Swnj * information to be at the front, but we still have to drop 4186471Sroot * the type and length which are at the front of any trailer data. 4195105Swnj */ 4205105Swnj m = if_rubaget(&es->es_ifuba, len, off); 4215213Swnj if (m == 0) 4225213Swnj goto setup; 4235105Swnj if (off) { 4246471Sroot m->m_off += 2 * sizeof (u_short); 4256471Sroot m->m_len -= 2 * sizeof (u_short); 4265105Swnj } 4276027Ssam switch (en->en_type) { 4286027Ssam 4296027Ssam #ifdef INET 43012352Ssam case ENTYPE_IP: 4316260Swnj schednetisr(NETISR_IP); 4326027Ssam inq = &ipintrq; 4336027Ssam break; 4346027Ssam #endif 4356335Ssam #ifdef PUP 436*13458Ssam case ENTYPE_PUP: 437*13458Ssam rpup_input(m); 4386027Ssam goto setup; 4396335Ssam #endif 4406476Swnj default: 441*13458Ssam #ifdef notdef 442*13458Ssam enproto.sp_protocol = en->en_type; 443*13458Ssam endst.sen_host = en->en_dhost; 444*13458Ssam endst.sen_net = ensrc.sen_net = es->es_if.if_net; 445*13458Ssam ensrc.sen_host = en->en_shost; 446*13458Ssam raw_input(m, &enproto, 447*13458Ssam (struct sockaddr *)&ensrc, (struct sockaddr *)&endst); 448*13458Ssam #else 4496476Swnj m_freem(m); 450*13458Ssam #endif 4516476Swnj goto setup; 4526335Ssam } 4536335Ssam 4546207Swnj if (IF_QFULL(inq)) { 4556207Swnj IF_DROP(inq); 4566335Ssam m_freem(m); 4576207Swnj } else 4586207Swnj IF_ENQUEUE(inq, m); 4595105Swnj 4604688Swnj setup: 4615105Swnj /* 4625105Swnj * Reset for next packet. 4635105Swnj */ 4645105Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 4656925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 4664771Swnj addr->en_istat = EN_IEN|EN_GO; 4674688Swnj } 4684686Swnj 4695083Swnj /* 4705083Swnj * Ethernet output routine. 4715083Swnj * Encapsulate a packet of type family for the local net. 4725105Swnj * Use trailer local net encapsulation if enough data in first 4735105Swnj * packet leaves a multiple of 512 bytes of data in remainder. 4745083Swnj */ 4756335Ssam enoutput(ifp, m0, dst) 4765083Swnj struct ifnet *ifp; 4775083Swnj struct mbuf *m0; 4786335Ssam struct sockaddr *dst; 4794686Swnj { 4806503Ssam int type, dest, s, error; 4815105Swnj register struct mbuf *m = m0; 4825083Swnj register struct en_header *en; 4836335Ssam register int off; 4844686Swnj 4856335Ssam switch (dst->sa_family) { 4865083Swnj 4875083Swnj #ifdef INET 4886335Ssam case AF_INET: 4896484Swnj dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 4909178Ssam if (in_lnaof(*((struct in_addr *)&dest)) >= 0x100) { 4916503Ssam error = EPERM; /* ??? */ 4926486Swnj goto bad; 4936503Ssam } 4946484Swnj dest = (dest >> 24) & 0xff; 4956335Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 49613054Ssam /* need per host negotiation */ 49713054Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 4986335Ssam if (off > 0 && (off & 0x1ff) == 0 && 4996471Sroot m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 50012352Ssam type = ENTYPE_TRAIL + (off>>9); 5016471Sroot m->m_off -= 2 * sizeof (u_short); 5026471Sroot m->m_len += 2 * sizeof (u_short); 50312352Ssam *mtod(m, u_short *) = htons((u_short)ENTYPE_IP); 50412352Ssam *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); 5055105Swnj goto gottrailertype; 5065083Swnj } 50712352Ssam type = ENTYPE_IP; 5085105Swnj off = 0; 5095105Swnj goto gottype; 5105083Swnj #endif 5116027Ssam #ifdef PUP 5126335Ssam case AF_PUP: 51312833Ssam dest = ((struct sockaddr_pup *)dst)->spup_host; 51412352Ssam type = ENTYPE_PUP; 5156027Ssam off = 0; 5166027Ssam goto gottype; 5176027Ssam #endif 5186027Ssam 519*13458Ssam #ifdef notdef 520*13458Ssam case AF_ETHERLINK: 521*13458Ssam goto gotheader; 522*13458Ssam #endif 523*13458Ssam 5245083Swnj default: 5256335Ssam printf("en%d: can't handle af%d\n", ifp->if_unit, 5266335Ssam dst->sa_family); 5276503Ssam error = EAFNOSUPPORT; 5286503Ssam goto bad; 5294686Swnj } 5305105Swnj 5315171Swnj gottrailertype: 5325105Swnj /* 5335105Swnj * Packet to be sent as trailer: move first packet 5345105Swnj * (control information) to end of chain. 5355105Swnj */ 5365105Swnj while (m->m_next) 5375105Swnj m = m->m_next; 5385105Swnj m->m_next = m0; 5395105Swnj m = m0->m_next; 5405105Swnj m0->m_next = 0; 5415171Swnj m0 = m; 5425105Swnj 5435171Swnj gottype: 5445105Swnj /* 5455105Swnj * Add local net header. If no space in first mbuf, 5465105Swnj * allocate another. 5475105Swnj */ 5485213Swnj if (m->m_off > MMAXOFF || 5495213Swnj MMINOFF + sizeof (struct en_header) > m->m_off) { 5509649Ssam m = m_get(M_DONTWAIT, MT_HEADER); 5515083Swnj if (m == 0) { 5526503Ssam error = ENOBUFS; 5536503Ssam goto bad; 5545083Swnj } 5555083Swnj m->m_next = m0; 5565083Swnj m->m_off = MMINOFF; 5575083Swnj m->m_len = sizeof (struct en_header); 5585083Swnj } else { 5595083Swnj m->m_off -= sizeof (struct en_header); 5605083Swnj m->m_len += sizeof (struct en_header); 5615083Swnj } 5625083Swnj en = mtod(m, struct en_header *); 5635083Swnj en->en_shost = ifp->if_host[0]; 5645083Swnj en->en_dhost = dest; 56512352Ssam en->en_type = htons((u_short)type); 5665105Swnj 567*13458Ssam gotheader: 5685105Swnj /* 5695105Swnj * Queue message on interface, and start output if interface 5705105Swnj * not yet active. 5715105Swnj */ 5725083Swnj s = splimp(); 5736207Swnj if (IF_QFULL(&ifp->if_snd)) { 5746207Swnj IF_DROP(&ifp->if_snd); 5756503Ssam error = ENOBUFS; 5766503Ssam goto qfull; 5776207Swnj } 5785083Swnj IF_ENQUEUE(&ifp->if_snd, m); 5795083Swnj if (en_softc[ifp->if_unit].es_oactive == 0) 5805083Swnj enstart(ifp->if_unit); 5815275Swnj splx(s); 5826503Ssam return (0); 5836503Ssam qfull: 5846503Ssam m0 = m; 5856503Ssam splx(s); 5866484Swnj bad: 5876503Ssam m_freem(m0); 5886503Ssam return (error); 5894686Swnj } 59013054Ssam 59113054Ssam /* 59213054Ssam * Process an ioctl request. 59313054Ssam */ 59413054Ssam enioctl(ifp, cmd, data) 59513054Ssam register struct ifnet *ifp; 59613054Ssam int cmd; 59713054Ssam caddr_t data; 59813054Ssam { 59913054Ssam struct ifreq *ifr = (struct ifreq *)data; 60013054Ssam int s = splimp(), error = 0; 60113054Ssam 60213054Ssam switch (cmd) { 60313054Ssam 60413054Ssam case SIOCSIFADDR: 60513054Ssam if (ifp->if_flags & IFF_RUNNING) 60613054Ssam if_rtinit(ifp, -1); /* delete previous route */ 60713054Ssam ensetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr); 60813054Ssam if (ifp->if_flags & IFF_RUNNING) 60913054Ssam if_rtinit(ifp, RTF_UP); 61013054Ssam else 61113054Ssam eninit(ifp->if_unit); 61213054Ssam break; 61313054Ssam 61413054Ssam default: 61513054Ssam error = EINVAL; 61613054Ssam } 61713054Ssam splx(s); 61813054Ssam return (error); 61913054Ssam } 62013054Ssam 62113054Ssam ensetaddr(ifp, sin) 62213054Ssam register struct ifnet *ifp; 62313054Ssam register struct sockaddr_in *sin; 62413054Ssam { 62513054Ssam struct endevice *enaddr; 62613054Ssam 62713054Ssam ifp->if_net = in_netof(sin->sin_addr); 62813054Ssam enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr; 62913054Ssam ifp->if_host[0] = (~enaddr->en_addr) & 0xff; 63013054Ssam sin = (struct sockaddr_in *)&ifp->if_addr; 63113054Ssam sin->sin_family = AF_INET; 63213054Ssam sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); 63313054Ssam sin = (struct sockaddr_in *)&ifp->if_broadaddr; 63413054Ssam sin->sin_family = AF_INET; 63513054Ssam sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 63613054Ssam ifp->if_flags |= IFF_BROADCAST; 63713054Ssam } 63813293Ssam 63913293Ssam #ifdef ENF_SWABIPS 64013293Ssam /* 64113293Ssam * Swab bytes 64213293Ssam * Jeffrey Mogul, Stanford 64313293Ssam */ 64413293Ssam enswab(from, to, n) 64513293Ssam register caddr_t *from, *to; 64613293Ssam register int n; 64713293Ssam { 64813293Ssam register unsigned long temp; 64913293Ssam 65013293Ssam n >>= 1; n++; 65113293Ssam #define STEP temp = *from++,*to++ = *from++,*to++ = temp 65213293Ssam /* round to multiple of 8 */ 65313293Ssam while ((--n) & 07) 65413293Ssam STEP; 65513293Ssam n >>= 3; 65613293Ssam while (--n >= 0) { 65713293Ssam STEP; STEP; STEP; STEP; 65813293Ssam STEP; STEP; STEP; STEP; 65913293Ssam } 66013293Ssam } 66113293Ssam #endif 662