1*12833Ssam /* if_en.c 4.78 83/05/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" 178462Sroot #include <errno.h> 188462Sroot 198462Sroot #include "../net/if.h" 208462Sroot #include "../net/netisr.h" 218462Sroot #include "../net/route.h" 228418Swnj #include "../netinet/in.h" 238418Swnj #include "../netinet/in_systm.h" 248418Swnj #include "../netinet/ip.h" 258418Swnj #include "../netinet/ip_var.h" 268418Swnj #include "../netpup/pup.h" 274686Swnj 288462Sroot #include "../vax/cpu.h" 298462Sroot #include "../vax/mtpr.h" 308462Sroot #include "../vaxif/if_en.h" 318462Sroot #include "../vaxif/if_enreg.h" 328462Sroot #include "../vaxif/if_uba.h" 338462Sroot #include "../vaxuba/ubareg.h" 348462Sroot #include "../vaxuba/ubavar.h" 358462Sroot 365213Swnj #define ENMTU (1024+512) 376925Swnj #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */ 385083Swnj 394686Swnj int enprobe(), enattach(), enrint(), enxint(), encollide(); 404686Swnj struct uba_device *eninfo[NEN]; 414686Swnj u_short enstd[] = { 0 }; 424686Swnj struct uba_driver endriver = 435171Swnj { enprobe, 0, enattach, 0, enstd, "en", eninfo }; 444686Swnj #define ENUNIT(x) minor(x) 454686Swnj 465105Swnj int eninit(),enoutput(),enreset(); 475105Swnj 485105Swnj /* 495105Swnj * Ethernet software status per interface. 505105Swnj * 515105Swnj * Each interface is referenced by a network interface structure, 525105Swnj * es_if, which the routing code uses to locate the interface. 535105Swnj * This structure contains the output queue for the interface, its address, ... 545105Swnj * We also have, for each interface, a UBA interface structure, which 555105Swnj * contains information about the UNIBUS resources held by the interface: 565105Swnj * map registers, buffered data paths, etc. Information is cached in this 575105Swnj * structure for use by the if_uba.c routines in running the interface 585105Swnj * efficiently. 595105Swnj */ 605083Swnj struct en_softc { 615105Swnj struct ifnet es_if; /* network-visible interface */ 625105Swnj struct ifuba es_ifuba; /* UNIBUS resources */ 635105Swnj short es_delay; /* current output delay */ 645105Swnj short es_mask; /* mask for current output delay */ 656471Sroot short es_lastx; /* host last transmitted to */ 665105Swnj short es_oactive; /* is output active? */ 675105Swnj short es_olen; /* length of last output */ 685083Swnj } en_softc[NEN]; 694686Swnj 705105Swnj /* 715105Swnj * Do output DMA to determine interface presence and 725105Swnj * interrupt vector. DMA is too short to disturb other hosts. 735105Swnj */ 744686Swnj enprobe(reg) 754686Swnj caddr_t reg; 764686Swnj { 775171Swnj register int br, cvec; /* r11, r10 value-result */ 784686Swnj register struct endevice *addr = (struct endevice *)reg; 794686Swnj 804686Swnj #ifdef lint 814686Swnj br = 0; cvec = br; br = cvec; 824922Swnj enrint(0); enxint(0); encollide(0); 834686Swnj #endif 844686Swnj addr->en_istat = 0; 854686Swnj addr->en_owc = -1; 864686Swnj addr->en_oba = 0; 874771Swnj addr->en_ostat = EN_IEN|EN_GO; 884686Swnj DELAY(100000); 894686Swnj addr->en_ostat = 0; 906575Ssam #ifdef ECHACK 916575Ssam br = 0x16; 926575Ssam #endif 934686Swnj return (1); 944686Swnj } 954686Swnj 965105Swnj /* 975105Swnj * Interface exists: make available by filling in network interface 985105Swnj * record. System will initialize the interface when it is ready 995105Swnj * to accept packets. 1005105Swnj */ 1014686Swnj enattach(ui) 1024686Swnj struct uba_device *ui; 1034686Swnj { 1045105Swnj register struct en_softc *es = &en_softc[ui->ui_unit]; 1054688Swnj 1065105Swnj es->es_if.if_unit = ui->ui_unit; 1075171Swnj es->es_if.if_name = "en"; 1085105Swnj es->es_if.if_mtu = ENMTU; 10912349Ssam if (ui->ui_flags) 11012349Ssam ensetaddr(es, ui->ui_flags); 1115171Swnj es->es_if.if_init = eninit; 1125105Swnj es->es_if.if_output = enoutput; 1138978Sroot es->es_if.if_reset = enreset; 1146554Ssam es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT; 1159271Ssam #if defined(VAX750) 1169271Ssam /* don't chew up 750 bdp's */ 1179271Ssam if (cpu == VAX_750 && ui->ui_unit > 0) 1189271Ssam es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP; 1199271Ssam #endif 1205160Swnj if_attach(&es->es_if); 1214686Swnj } 1224686Swnj 1235105Swnj /* 12412349Ssam * Set interface's Internet address 12512349Ssam * given the network number. The station 12612349Ssam * number, taken from the on-board register, 12712349Ssam * is used as the local part. 12812349Ssam */ 12912349Ssam ensetaddr(es, net) 13012349Ssam register struct en_softc *es; 13112349Ssam int net; 13212349Ssam { 13312349Ssam struct endevice *enaddr; 13412349Ssam register struct sockaddr_in *sin; 13512349Ssam 13612349Ssam es->es_if.if_net = net; 13712349Ssam enaddr = (struct endevice *)eninfo[es->es_if.if_unit]->ui_addr; 13812349Ssam es->es_if.if_host[0] = (~enaddr->en_addr) & 0xff; 13912349Ssam sin = (struct sockaddr_in *)&es->es_if.if_addr; 14012349Ssam sin->sin_family = AF_INET; 14112349Ssam sin->sin_addr = if_makeaddr(net, es->es_if.if_host[0]); 14212349Ssam sin = (struct sockaddr_in *)&es->es_if.if_broadaddr; 14312349Ssam sin->sin_family = AF_INET; 14412349Ssam sin->sin_addr = if_makeaddr(net, INADDR_ANY); 14512349Ssam es->es_if.if_flags |= IFF_BROADCAST; 14612349Ssam } 14712349Ssam 14812349Ssam /* 1495105Swnj * Reset of interface after UNIBUS reset. 1505105Swnj * If interface is on specified uba, reset its state. 1515105Swnj */ 1525105Swnj enreset(unit, uban) 1535105Swnj int unit, uban; 1545105Swnj { 1555105Swnj register struct uba_device *ui; 1565105Swnj 1575171Swnj if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || 1585171Swnj ui->ui_ubanum != uban) 1595105Swnj return; 1605171Swnj printf(" en%d", unit); 1615105Swnj eninit(unit); 1625105Swnj } 1635105Swnj 1645105Swnj /* 1655105Swnj * Initialization of interface; clear recorded pending 1665105Swnj * operations, and reinitialize UNIBUS usage. 1675105Swnj */ 1684688Swnj eninit(unit) 1694686Swnj int unit; 1705083Swnj { 1715171Swnj register struct en_softc *es = &en_softc[unit]; 1725171Swnj register struct uba_device *ui = eninfo[unit]; 1734686Swnj register struct endevice *addr; 17412349Ssam struct sockaddr_in *sin = (struct sockaddr_in *)&es->es_if.if_addr; 17512349Ssam int net, s; 1764686Swnj 17712349Ssam net = in_netof(sin->sin_addr); 17812349Ssam if (net == 0) 17912349Ssam return; 18012349Ssam ensetaddr(es, net); 18112349Ssam #ifdef notdef 18212349Ssam if (es->es_if.if_flags & IFF_UP) 18312349Ssam return; 18412349Ssam #endif 1855105Swnj if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 1866925Swnj sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 1875171Swnj printf("en%d: can't initialize\n", unit); 1886335Ssam es->es_if.if_flags &= ~IFF_UP; 1895083Swnj return; 1904686Swnj } 1914686Swnj addr = (struct endevice *)ui->ui_addr; 1925083Swnj addr->en_istat = addr->en_ostat = 0; 1934686Swnj 1945105Swnj /* 1955171Swnj * Hang a receive and start any 1965171Swnj * pending writes by faking a transmit complete. 1975105Swnj */ 1985105Swnj s = splimp(); 1995171Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 2006925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 2015171Swnj addr->en_istat = EN_IEN|EN_GO; 2025171Swnj es->es_oactive = 1; 2036335Ssam es->es_if.if_flags |= IFF_UP; 2045105Swnj enxint(unit); 2055105Swnj splx(s); 2067151Swnj if_rtinit(&es->es_if, RTF_UP); 2074686Swnj } 2084686Swnj 2096471Sroot int enalldelay = 0; 2106951Swnj int enlastdel = 50; 2116471Sroot int enlastmask = (~0) << 5; 2125083Swnj 2135105Swnj /* 2145105Swnj * Start or restart output on interface. 2155105Swnj * If interface is already active, then this is a retransmit 2165105Swnj * after a collision, and just restuff registers and delay. 2175105Swnj * If interface is not already active, get another datagram 2185105Swnj * to send off of the interface queue, and map it to the interface 2195105Swnj * before starting the output. 2205105Swnj */ 2214688Swnj enstart(dev) 2224686Swnj dev_t dev; 2234686Swnj { 2245171Swnj int unit = ENUNIT(dev); 2255171Swnj struct uba_device *ui = eninfo[unit]; 2265171Swnj register struct en_softc *es = &en_softc[unit]; 2275083Swnj register struct endevice *addr; 2285083Swnj struct mbuf *m; 2295083Swnj int dest; 2304686Swnj 2315083Swnj if (es->es_oactive) 2325083Swnj goto restart; 2335105Swnj 2345105Swnj /* 2355105Swnj * Not already active: dequeue another request 2365105Swnj * and map it to the UNIBUS. If no more requests, 2375105Swnj * just return. 2385105Swnj */ 2395105Swnj IF_DEQUEUE(&es->es_if.if_snd, m); 2405083Swnj if (m == 0) { 2415083Swnj es->es_oactive = 0; 2424686Swnj return; 2434686Swnj } 2445213Swnj dest = mtod(m, struct en_header *)->en_dhost; 2455105Swnj es->es_olen = if_wubaput(&es->es_ifuba, m); 2465105Swnj 2475105Swnj /* 2485105Swnj * Ethernet cannot take back-to-back packets (no 2496471Sroot * buffering in interface. To help avoid overrunning 2506471Sroot * receivers, enforce a small delay (about 1ms) in interface: 2516471Sroot * * between all packets when enalldelay 2526471Sroot * * whenever last packet was broadcast 2536471Sroot * * whenever this packet is to same host as last packet 2545105Swnj */ 2556471Sroot if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 2565083Swnj es->es_delay = enlastdel; 2576471Sroot es->es_mask = enlastmask; 2586471Sroot } 2596471Sroot es->es_lastx = dest; 2605105Swnj 2615083Swnj restart: 2625105Swnj /* 2635105Swnj * Have request mapped to UNIBUS for transmission. 2645105Swnj * Purge any stale data from this BDP, and start the otput. 2655105Swnj */ 2666335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 2676335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 2684686Swnj addr = (struct endevice *)ui->ui_addr; 2695160Swnj addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 2705083Swnj addr->en_odelay = es->es_delay; 2715083Swnj addr->en_owc = -((es->es_olen + 1) >> 1); 2724771Swnj addr->en_ostat = EN_IEN|EN_GO; 2735083Swnj es->es_oactive = 1; 2744686Swnj } 2754686Swnj 2765105Swnj /* 2775105Swnj * Ethernet interface transmitter interrupt. 2785105Swnj * Start another output if more data to send. 2795105Swnj */ 2804686Swnj enxint(unit) 2814686Swnj int unit; 2824686Swnj { 2835171Swnj register struct uba_device *ui = eninfo[unit]; 2845171Swnj register struct en_softc *es = &en_softc[unit]; 2856242Sroot register struct endevice *addr = (struct endevice *)ui->ui_addr; 2864686Swnj 2875083Swnj if (es->es_oactive == 0) 2885083Swnj return; 2896242Sroot if (es->es_mask && (addr->en_ostat&EN_OERROR)) { 2906242Sroot es->es_if.if_oerrors++; 2916242Sroot endocoll(unit); 2926242Sroot return; 2936242Sroot } 2945171Swnj es->es_if.if_opackets++; 2955083Swnj es->es_oactive = 0; 2965083Swnj es->es_delay = 0; 2975083Swnj es->es_mask = ~0; 2985696Sroot if (es->es_ifuba.ifu_xtofree) { 2995696Sroot m_freem(es->es_ifuba.ifu_xtofree); 3005696Sroot es->es_ifuba.ifu_xtofree = 0; 3015696Sroot } 3025105Swnj if (es->es_if.if_snd.ifq_head == 0) { 3036471Sroot es->es_lastx = 256; /* putatively illegal */ 3044686Swnj return; 3054686Swnj } 3065083Swnj enstart(unit); 3074686Swnj } 3084686Swnj 3095105Swnj /* 3105105Swnj * Collision on ethernet interface. Do exponential 3115105Swnj * backoff, and retransmit. If have backed off all 3126335Ssam * the way print warning diagnostic, and drop packet. 3135105Swnj */ 3144686Swnj encollide(unit) 3154686Swnj int unit; 3164686Swnj { 3176242Sroot struct en_softc *es = &en_softc[unit]; 3184686Swnj 3195105Swnj es->es_if.if_collisions++; 3205083Swnj if (es->es_oactive == 0) 3214686Swnj return; 3226242Sroot endocoll(unit); 3236242Sroot } 3246242Sroot 3256242Sroot endocoll(unit) 3266242Sroot int unit; 3276242Sroot { 3286242Sroot register struct en_softc *es = &en_softc[unit]; 3296242Sroot 3305171Swnj /* 3315171Swnj * Es_mask is a 16 bit number with n low zero bits, with 3325171Swnj * n the number of backoffs. When es_mask is 0 we have 3335171Swnj * backed off 16 times, and give up. 3345171Swnj */ 3355083Swnj if (es->es_mask == 0) { 3365213Swnj printf("en%d: send error\n", unit); 3375083Swnj enxint(unit); 3385171Swnj return; 3394686Swnj } 3405171Swnj /* 3415171Swnj * Another backoff. Restart with delay based on n low bits 3425171Swnj * of the interval timer. 3435171Swnj */ 3445171Swnj es->es_mask <<= 1; 3455171Swnj es->es_delay = mfpr(ICR) &~ es->es_mask; 3465171Swnj enstart(unit); 3474686Swnj } 3484686Swnj 3496027Ssam struct sockaddr_pup pupsrc = { AF_PUP }; 3506027Ssam struct sockaddr_pup pupdst = { AF_PUP }; 3516027Ssam struct sockproto pupproto = { PF_PUP }; 3525105Swnj /* 3535105Swnj * Ethernet interface receiver interrupt. 3545105Swnj * If input error just drop packet. 3555105Swnj * Otherwise purge input buffered data path and examine 3565105Swnj * packet to determine type. If can't determine length 3575105Swnj * from type, then have to drop packet. Othewise decapsulate 3585105Swnj * packet based on type and pass to type specific higher-level 3595105Swnj * input routine. 3605105Swnj */ 3614686Swnj enrint(unit) 3624686Swnj int unit; 3634686Swnj { 3645171Swnj register struct en_softc *es = &en_softc[unit]; 3655171Swnj struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; 3665171Swnj register struct en_header *en; 3675083Swnj struct mbuf *m; 3688603Sroot int len; short resid; 3695171Swnj register struct ifqueue *inq; 3705083Swnj int off; 3714686Swnj 3725171Swnj es->es_if.if_ipackets++; 3735105Swnj 3745105Swnj /* 3755171Swnj * Purge BDP; drop if input error indicated. 3765105Swnj */ 3776335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 3786335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 3794771Swnj if (addr->en_istat&EN_IERROR) { 3805105Swnj es->es_if.if_ierrors++; 3815083Swnj goto setup; 3824686Swnj } 3835105Swnj 3845105Swnj /* 3856471Sroot * Calculate input data length. 3865105Swnj * Get pointer to ethernet header (in input buffer). 3875105Swnj * Deal with trailer protocol: if type is PUP trailer 3885105Swnj * get true type from first 16-bit word past data. 3895105Swnj * Remember that type was trailer by setting off. 3905105Swnj */ 3916471Sroot resid = addr->en_iwc; 3926471Sroot if (resid) 3936471Sroot resid |= 0176000; 3946925Swnj len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1; 3956471Sroot len -= sizeof (struct en_header); 3966925Swnj if (len > ENMRU) 3976471Sroot goto setup; /* sanity */ 3985105Swnj en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 39912352Ssam en->en_type = ntohs(en->en_type); 4005083Swnj #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 40112352Ssam if (en->en_type >= ENTYPE_TRAIL && 40212352Ssam en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) { 40312352Ssam off = (en->en_type - ENTYPE_TRAIL) * 512; 4046925Swnj if (off > ENMTU) 4055171Swnj goto setup; /* sanity */ 40612352Ssam en->en_type = ntohs(*endataaddr(en, off, u_short *)); 40712352Ssam resid = ntohs(*(endataaddr(en, off+2, u_short *))); 4086471Sroot if (off + resid > len) 4096471Sroot goto setup; /* sanity */ 4106471Sroot len = off + resid; 4115083Swnj } else 4125083Swnj off = 0; 4135083Swnj if (len == 0) 4145083Swnj goto setup; 4155105Swnj /* 4165105Swnj * Pull packet off interface. Off is nonzero if packet 4175105Swnj * has trailing header; if_rubaget will then force this header 4185105Swnj * information to be at the front, but we still have to drop 4196471Sroot * the type and length which are at the front of any trailer data. 4205105Swnj */ 4215105Swnj m = if_rubaget(&es->es_ifuba, len, off); 4225213Swnj if (m == 0) 4235213Swnj goto setup; 4245105Swnj if (off) { 4256471Sroot m->m_off += 2 * sizeof (u_short); 4266471Sroot m->m_len -= 2 * sizeof (u_short); 4275105Swnj } 4286027Ssam switch (en->en_type) { 4296027Ssam 4306027Ssam #ifdef INET 43112352Ssam case ENTYPE_IP: 4326260Swnj schednetisr(NETISR_IP); 4336027Ssam inq = &ipintrq; 4346027Ssam break; 4356027Ssam #endif 4366335Ssam #ifdef PUP 43712352Ssam case ENTYPE_PUP: { 4386027Ssam struct pup_header *pup = mtod(m, struct pup_header *); 4396027Ssam 4406027Ssam pupproto.sp_protocol = pup->pup_type; 441*12833Ssam bcopy((caddr_t)pup->pup_dnet, (caddr_t)pupdst.spup_net, 442*12833Ssam sizeof (struct pupport)); 443*12833Ssam bcopy((caddr_t)pup->pup_snet, (caddr_t)pupsrc.spup_net, 444*12833Ssam sizeof (struct pupport)); 4456526Ssam raw_input(m, &pupproto, (struct sockaddr *)&pupsrc, 4466526Ssam (struct sockaddr *)&pupdst); 4476027Ssam goto setup; 4486027Ssam } 4496335Ssam #endif 4506476Swnj default: 4516476Swnj m_freem(m); 4526476Swnj goto setup; 4536335Ssam } 4546335Ssam 4556207Swnj if (IF_QFULL(inq)) { 4566207Swnj IF_DROP(inq); 4576335Ssam m_freem(m); 4586207Swnj } else 4596207Swnj IF_ENQUEUE(inq, m); 4605105Swnj 4614688Swnj setup: 4625105Swnj /* 4635105Swnj * Reset for next packet. 4645105Swnj */ 4655105Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 4666925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 4674771Swnj addr->en_istat = EN_IEN|EN_GO; 4684688Swnj } 4694686Swnj 4705083Swnj /* 4715083Swnj * Ethernet output routine. 4725083Swnj * Encapsulate a packet of type family for the local net. 4735105Swnj * Use trailer local net encapsulation if enough data in first 4745105Swnj * packet leaves a multiple of 512 bytes of data in remainder. 4755083Swnj */ 4766335Ssam enoutput(ifp, m0, dst) 4775083Swnj struct ifnet *ifp; 4785083Swnj struct mbuf *m0; 4796335Ssam struct sockaddr *dst; 4804686Swnj { 4816503Ssam int type, dest, s, error; 4825105Swnj register struct mbuf *m = m0; 4835083Swnj register struct en_header *en; 4846335Ssam register int off; 4854686Swnj 4866335Ssam switch (dst->sa_family) { 4875083Swnj 4885083Swnj #ifdef INET 4896335Ssam case AF_INET: 4906484Swnj dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 4919178Ssam if (in_lnaof(*((struct in_addr *)&dest)) >= 0x100) { 4926503Ssam error = EPERM; /* ??? */ 4936486Swnj goto bad; 4946503Ssam } 4956484Swnj dest = (dest >> 24) & 0xff; 4966335Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 4976335Ssam if (off > 0 && (off & 0x1ff) == 0 && 4986471Sroot m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 49912352Ssam type = ENTYPE_TRAIL + (off>>9); 5006471Sroot m->m_off -= 2 * sizeof (u_short); 5016471Sroot m->m_len += 2 * sizeof (u_short); 50212352Ssam *mtod(m, u_short *) = htons((u_short)ENTYPE_IP); 50312352Ssam *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); 5045105Swnj goto gottrailertype; 5055083Swnj } 50612352Ssam type = ENTYPE_IP; 5075105Swnj off = 0; 5085105Swnj goto gottype; 5095083Swnj #endif 5106027Ssam #ifdef PUP 5116335Ssam case AF_PUP: 512*12833Ssam dest = ((struct sockaddr_pup *)dst)->spup_host; 51312352Ssam type = ENTYPE_PUP; 5146027Ssam off = 0; 5156027Ssam goto gottype; 5166027Ssam #endif 5176027Ssam 5185083Swnj default: 5196335Ssam printf("en%d: can't handle af%d\n", ifp->if_unit, 5206335Ssam dst->sa_family); 5216503Ssam error = EAFNOSUPPORT; 5226503Ssam goto bad; 5234686Swnj } 5245105Swnj 5255171Swnj gottrailertype: 5265105Swnj /* 5275105Swnj * Packet to be sent as trailer: move first packet 5285105Swnj * (control information) to end of chain. 5295105Swnj */ 5305105Swnj while (m->m_next) 5315105Swnj m = m->m_next; 5325105Swnj m->m_next = m0; 5335105Swnj m = m0->m_next; 5345105Swnj m0->m_next = 0; 5355171Swnj m0 = m; 5365105Swnj 5375171Swnj gottype: 5385105Swnj /* 5395105Swnj * Add local net header. If no space in first mbuf, 5405105Swnj * allocate another. 5415105Swnj */ 5425213Swnj if (m->m_off > MMAXOFF || 5435213Swnj MMINOFF + sizeof (struct en_header) > m->m_off) { 5449649Ssam m = m_get(M_DONTWAIT, MT_HEADER); 5455083Swnj if (m == 0) { 5466503Ssam error = ENOBUFS; 5476503Ssam goto bad; 5485083Swnj } 5495083Swnj m->m_next = m0; 5505083Swnj m->m_off = MMINOFF; 5515083Swnj m->m_len = sizeof (struct en_header); 5525083Swnj } else { 5535083Swnj m->m_off -= sizeof (struct en_header); 5545083Swnj m->m_len += sizeof (struct en_header); 5555083Swnj } 5565083Swnj en = mtod(m, struct en_header *); 5575083Swnj en->en_shost = ifp->if_host[0]; 5585083Swnj en->en_dhost = dest; 55912352Ssam en->en_type = htons((u_short)type); 5605105Swnj 5615105Swnj /* 5625105Swnj * Queue message on interface, and start output if interface 5635105Swnj * not yet active. 5645105Swnj */ 5655083Swnj s = splimp(); 5666207Swnj if (IF_QFULL(&ifp->if_snd)) { 5676207Swnj IF_DROP(&ifp->if_snd); 5686503Ssam error = ENOBUFS; 5696503Ssam goto qfull; 5706207Swnj } 5715083Swnj IF_ENQUEUE(&ifp->if_snd, m); 5725083Swnj if (en_softc[ifp->if_unit].es_oactive == 0) 5735083Swnj enstart(ifp->if_unit); 5745275Swnj splx(s); 5756503Ssam return (0); 5766503Ssam qfull: 5776503Ssam m0 = m; 5786503Ssam splx(s); 5796484Swnj bad: 5806503Ssam m_freem(m0); 5816503Ssam return (error); 5824686Swnj } 583