123290Smckusick /* 223290Smckusick * Copyright (c) 1982 Regents of the University of California. 323290Smckusick * All rights reserved. The Berkeley software License Agreement 423290Smckusick * specifies the terms and conditions for redistribution. 523290Smckusick * 6*24790Skarels * @(#)if_en.c 6.9 (Berkeley) 09/16/85 723290Smckusick */ 84686Swnj 94686Swnj #include "en.h" 105105Swnj 114686Swnj /* 125105Swnj * Xerox prototype (3 Mb) Ethernet interface driver. 134686Swnj */ 149796Ssam #include "../machine/pte.h" 154686Swnj 1617113Sbloom #include "param.h" 1717113Sbloom #include "systm.h" 1817113Sbloom #include "mbuf.h" 1917113Sbloom #include "buf.h" 2017113Sbloom #include "protosw.h" 2117113Sbloom #include "socket.h" 2217113Sbloom #include "vmmac.h" 2317113Sbloom #include "errno.h" 2417113Sbloom #include "ioctl.h" 258462Sroot 268462Sroot #include "../net/if.h" 278462Sroot #include "../net/netisr.h" 288462Sroot #include "../net/route.h" 29*24790Skarels 30*24790Skarels #ifdef BBNNET 31*24790Skarels #define INET 32*24790Skarels #endif 33*24790Skarels #ifdef INET 348418Swnj #include "../netinet/in.h" 358418Swnj #include "../netinet/in_systm.h" 3619864Skarels #include "../netinet/in_var.h" 378418Swnj #include "../netinet/ip.h" 38*24790Skarels #endif 39*24790Skarels 4019950Sbloom #ifdef PUP 418418Swnj #include "../netpup/pup.h" 4213458Ssam #include "../netpup/ether.h" 4319950Sbloom #endif 444686Swnj 458462Sroot #include "../vax/cpu.h" 468462Sroot #include "../vax/mtpr.h" 4717113Sbloom #include "if_en.h" 4817113Sbloom #include "if_enreg.h" 4917113Sbloom #include "if_uba.h" 508462Sroot #include "../vaxuba/ubareg.h" 518462Sroot #include "../vaxuba/ubavar.h" 528462Sroot 535213Swnj #define ENMTU (1024+512) 546925Swnj #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */ 555083Swnj 564686Swnj int enprobe(), enattach(), enrint(), enxint(), encollide(); 574686Swnj struct uba_device *eninfo[NEN]; 584686Swnj u_short enstd[] = { 0 }; 594686Swnj struct uba_driver endriver = 605171Swnj { enprobe, 0, enattach, 0, enstd, "en", eninfo }; 614686Swnj #define ENUNIT(x) minor(x) 624686Swnj 6313054Ssam int eninit(),enoutput(),enreset(),enioctl(); 645105Swnj 6513293Ssam #ifdef notdef 665105Swnj /* 6713293Ssam * If you need to byte swap IP's in the system, define 6813293Ssam * this and do a SIOCSIFFLAGS at boot time. 6913293Ssam */ 7019864Skarels #define ENF_SWABIPS 0x1000 7113293Ssam #endif 7213293Ssam 7313293Ssam /* 745105Swnj * Ethernet software status per interface. 755105Swnj * 765105Swnj * Each interface is referenced by a network interface structure, 775105Swnj * es_if, which the routing code uses to locate the interface. 785105Swnj * This structure contains the output queue for the interface, its address, ... 795105Swnj * We also have, for each interface, a UBA interface structure, which 805105Swnj * contains information about the UNIBUS resources held by the interface: 815105Swnj * map registers, buffered data paths, etc. Information is cached in this 825105Swnj * structure for use by the if_uba.c routines in running the interface 835105Swnj * efficiently. 845105Swnj */ 855083Swnj struct en_softc { 865105Swnj struct ifnet es_if; /* network-visible interface */ 875105Swnj struct ifuba es_ifuba; /* UNIBUS resources */ 8816380Skarels short es_host; /* hardware host number */ 895105Swnj short es_delay; /* current output delay */ 905105Swnj short es_mask; /* mask for current output delay */ 916471Sroot short es_lastx; /* host last transmitted to */ 925105Swnj short es_oactive; /* is output active? */ 935105Swnj short es_olen; /* length of last output */ 945083Swnj } en_softc[NEN]; 954686Swnj 965105Swnj /* 975105Swnj * Do output DMA to determine interface presence and 985105Swnj * interrupt vector. DMA is too short to disturb other hosts. 995105Swnj */ 1004686Swnj enprobe(reg) 1014686Swnj caddr_t reg; 1024686Swnj { 1035171Swnj register int br, cvec; /* r11, r10 value-result */ 1044686Swnj register struct endevice *addr = (struct endevice *)reg; 1054686Swnj 1064686Swnj #ifdef lint 1074686Swnj br = 0; cvec = br; br = cvec; 1084922Swnj enrint(0); enxint(0); encollide(0); 1094686Swnj #endif 1104686Swnj addr->en_istat = 0; 1114686Swnj addr->en_owc = -1; 1124686Swnj addr->en_oba = 0; 1134771Swnj addr->en_ostat = EN_IEN|EN_GO; 1144686Swnj DELAY(100000); 1154686Swnj addr->en_ostat = 0; 1164686Swnj return (1); 1174686Swnj } 1184686Swnj 1195105Swnj /* 1205105Swnj * Interface exists: make available by filling in network interface 1215105Swnj * record. System will initialize the interface when it is ready 1225105Swnj * to accept packets. 1235105Swnj */ 1244686Swnj enattach(ui) 1254686Swnj struct uba_device *ui; 1264686Swnj { 1275105Swnj register struct en_softc *es = &en_softc[ui->ui_unit]; 1284688Swnj 1295105Swnj es->es_if.if_unit = ui->ui_unit; 1305171Swnj es->es_if.if_name = "en"; 1315105Swnj es->es_if.if_mtu = ENMTU; 13219864Skarels es->es_if.if_flags = IFF_BROADCAST; 1335171Swnj es->es_if.if_init = eninit; 1345105Swnj es->es_if.if_output = enoutput; 13513054Ssam es->es_if.if_ioctl = enioctl; 1368978Sroot es->es_if.if_reset = enreset; 1376554Ssam es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT; 1389271Ssam #if defined(VAX750) 1399271Ssam /* don't chew up 750 bdp's */ 1409271Ssam if (cpu == VAX_750 && ui->ui_unit > 0) 1419271Ssam es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP; 1429271Ssam #endif 1435160Swnj if_attach(&es->es_if); 1444686Swnj } 1454686Swnj 1465105Swnj /* 1475105Swnj * Reset of interface after UNIBUS reset. 1485105Swnj * If interface is on specified uba, reset its state. 1495105Swnj */ 1505105Swnj enreset(unit, uban) 1515105Swnj int unit, uban; 1525105Swnj { 1535105Swnj register struct uba_device *ui; 1545105Swnj 1555171Swnj if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || 1565171Swnj ui->ui_ubanum != uban) 1575105Swnj return; 1585171Swnj printf(" en%d", unit); 1595105Swnj eninit(unit); 1605105Swnj } 1615105Swnj 1625105Swnj /* 1635105Swnj * Initialization of interface; clear recorded pending 1645105Swnj * operations, and reinitialize UNIBUS usage. 1655105Swnj */ 1664688Swnj eninit(unit) 1674686Swnj int unit; 1685083Swnj { 1695171Swnj register struct en_softc *es = &en_softc[unit]; 1705171Swnj register struct uba_device *ui = eninfo[unit]; 1714686Swnj register struct endevice *addr; 17213054Ssam int s; 1734686Swnj 17419864Skarels if (es->es_if.if_addrlist == (struct ifaddr *)0) 17512349Ssam return; 1765105Swnj if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 1776925Swnj sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 1785171Swnj printf("en%d: can't initialize\n", unit); 1796335Ssam es->es_if.if_flags &= ~IFF_UP; 1805083Swnj return; 1814686Swnj } 1824686Swnj addr = (struct endevice *)ui->ui_addr; 1835083Swnj addr->en_istat = addr->en_ostat = 0; 1844686Swnj 1855105Swnj /* 1865171Swnj * Hang a receive and start any 1875171Swnj * pending writes by faking a transmit complete. 1885105Swnj */ 1895105Swnj s = splimp(); 1905171Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 1916925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 1925171Swnj addr->en_istat = EN_IEN|EN_GO; 1935171Swnj es->es_oactive = 1; 19419864Skarels es->es_if.if_flags |= IFF_RUNNING; 1955105Swnj enxint(unit); 1965105Swnj splx(s); 1974686Swnj } 1984686Swnj 1996471Sroot int enalldelay = 0; 2006951Swnj int enlastdel = 50; 2016471Sroot int enlastmask = (~0) << 5; 2025083Swnj 2035105Swnj /* 2045105Swnj * Start or restart output on interface. 2055105Swnj * If interface is already active, then this is a retransmit 2065105Swnj * after a collision, and just restuff registers and delay. 2075105Swnj * If interface is not already active, get another datagram 2085105Swnj * to send off of the interface queue, and map it to the interface 2095105Swnj * before starting the output. 2105105Swnj */ 2114688Swnj enstart(dev) 2124686Swnj dev_t dev; 2134686Swnj { 2145171Swnj int unit = ENUNIT(dev); 2155171Swnj struct uba_device *ui = eninfo[unit]; 2165171Swnj register struct en_softc *es = &en_softc[unit]; 2175083Swnj register struct endevice *addr; 21816380Skarels register struct en_header *en; 2195083Swnj struct mbuf *m; 2205083Swnj int dest; 2214686Swnj 2225083Swnj if (es->es_oactive) 2235083Swnj goto restart; 2245105Swnj 2255105Swnj /* 2265105Swnj * Not already active: dequeue another request 2275105Swnj * and map it to the UNIBUS. If no more requests, 2285105Swnj * just return. 2295105Swnj */ 2305105Swnj IF_DEQUEUE(&es->es_if.if_snd, m); 2315083Swnj if (m == 0) { 2325083Swnj es->es_oactive = 0; 2334686Swnj return; 2344686Swnj } 23516380Skarels en = mtod(m, struct en_header *); 23616380Skarels dest = en->en_dhost; 23716380Skarels en->en_shost = es->es_host; 2385105Swnj es->es_olen = if_wubaput(&es->es_ifuba, m); 23913293Ssam #ifdef ENF_SWABIPS 24013293Ssam /* 24113293Ssam * The Xerox interface does word at a time DMA, so 24213293Ssam * someone must do byte swapping of user data if high 24313293Ssam * and low ender machines are to communicate. It doesn't 24413293Ssam * belong here, but certain people depend on it, so... 24513293Ssam * 24613293Ssam * Should swab everybody, but this is a kludge anyway. 24713293Ssam */ 24813293Ssam if (es->es_if.if_flags & ENF_SWABIPS) { 24913293Ssam en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr; 25013293Ssam if (en->en_type == ENTYPE_IP) 25113293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), 25213293Ssam es->es_olen - sizeof (struct en_header) + 1); 25313293Ssam } 25413293Ssam #endif 25513293Ssam 2565105Swnj /* 2575105Swnj * Ethernet cannot take back-to-back packets (no 2586471Sroot * buffering in interface. To help avoid overrunning 2596471Sroot * receivers, enforce a small delay (about 1ms) in interface: 2606471Sroot * * between all packets when enalldelay 2616471Sroot * * whenever last packet was broadcast 2626471Sroot * * whenever this packet is to same host as last packet 2635105Swnj */ 2646471Sroot if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 2655083Swnj es->es_delay = enlastdel; 2666471Sroot es->es_mask = enlastmask; 2676471Sroot } 2686471Sroot es->es_lastx = dest; 2695105Swnj 2705083Swnj restart: 2715105Swnj /* 2725105Swnj * Have request mapped to UNIBUS for transmission. 2735105Swnj * Purge any stale data from this BDP, and start the otput. 2745105Swnj */ 2756335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 2766335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 2774686Swnj addr = (struct endevice *)ui->ui_addr; 2785160Swnj addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 2795083Swnj addr->en_odelay = es->es_delay; 2805083Swnj addr->en_owc = -((es->es_olen + 1) >> 1); 2814771Swnj addr->en_ostat = EN_IEN|EN_GO; 2825083Swnj es->es_oactive = 1; 2834686Swnj } 2844686Swnj 2855105Swnj /* 2865105Swnj * Ethernet interface transmitter interrupt. 2875105Swnj * Start another output if more data to send. 2885105Swnj */ 2894686Swnj enxint(unit) 2904686Swnj int unit; 2914686Swnj { 2925171Swnj register struct uba_device *ui = eninfo[unit]; 2935171Swnj register struct en_softc *es = &en_softc[unit]; 2946242Sroot register struct endevice *addr = (struct endevice *)ui->ui_addr; 2954686Swnj 2965083Swnj if (es->es_oactive == 0) 2975083Swnj return; 2986242Sroot if (es->es_mask && (addr->en_ostat&EN_OERROR)) { 2996242Sroot es->es_if.if_oerrors++; 3006242Sroot endocoll(unit); 3016242Sroot return; 3026242Sroot } 3035171Swnj es->es_if.if_opackets++; 3045083Swnj es->es_oactive = 0; 3055083Swnj es->es_delay = 0; 3065083Swnj es->es_mask = ~0; 3075696Sroot if (es->es_ifuba.ifu_xtofree) { 3085696Sroot m_freem(es->es_ifuba.ifu_xtofree); 3095696Sroot es->es_ifuba.ifu_xtofree = 0; 3105696Sroot } 3115105Swnj if (es->es_if.if_snd.ifq_head == 0) { 3126471Sroot es->es_lastx = 256; /* putatively illegal */ 3134686Swnj return; 3144686Swnj } 3155083Swnj enstart(unit); 3164686Swnj } 3174686Swnj 3185105Swnj /* 3195105Swnj * Collision on ethernet interface. Do exponential 3205105Swnj * backoff, and retransmit. If have backed off all 3216335Ssam * the way print warning diagnostic, and drop packet. 3225105Swnj */ 3234686Swnj encollide(unit) 3244686Swnj int unit; 3254686Swnj { 3266242Sroot struct en_softc *es = &en_softc[unit]; 3274686Swnj 3285105Swnj es->es_if.if_collisions++; 3295083Swnj if (es->es_oactive == 0) 3304686Swnj return; 3316242Sroot endocoll(unit); 3326242Sroot } 3336242Sroot 3346242Sroot endocoll(unit) 3356242Sroot int unit; 3366242Sroot { 3376242Sroot register struct en_softc *es = &en_softc[unit]; 3386242Sroot 3395171Swnj /* 3405171Swnj * Es_mask is a 16 bit number with n low zero bits, with 3415171Swnj * n the number of backoffs. When es_mask is 0 we have 3425171Swnj * backed off 16 times, and give up. 3435171Swnj */ 3445083Swnj if (es->es_mask == 0) { 3455213Swnj printf("en%d: send error\n", unit); 3465083Swnj enxint(unit); 3475171Swnj return; 3484686Swnj } 3495171Swnj /* 3505171Swnj * Another backoff. Restart with delay based on n low bits 3515171Swnj * of the interval timer. 3525171Swnj */ 3535171Swnj es->es_mask <<= 1; 3545171Swnj es->es_delay = mfpr(ICR) &~ es->es_mask; 3555171Swnj enstart(unit); 3564686Swnj } 3574686Swnj 35813458Ssam #ifdef notdef 35913458Ssam struct sockproto enproto = { AF_ETHERLINK }; 36013458Ssam struct sockaddr_en endst = { AF_ETHERLINK }; 36113458Ssam struct sockaddr_en ensrc = { AF_ETHERLINK }; 36213458Ssam #endif 3635105Swnj /* 3645105Swnj * Ethernet interface receiver interrupt. 3655105Swnj * If input error just drop packet. 3665105Swnj * Otherwise purge input buffered data path and examine 3675105Swnj * packet to determine type. If can't determine length 3685105Swnj * from type, then have to drop packet. Othewise decapsulate 3695105Swnj * packet based on type and pass to type specific higher-level 3705105Swnj * input routine. 3715105Swnj */ 3724686Swnj enrint(unit) 3734686Swnj int unit; 3744686Swnj { 3755171Swnj register struct en_softc *es = &en_softc[unit]; 3765171Swnj struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; 3775171Swnj register struct en_header *en; 3785083Swnj struct mbuf *m; 3798603Sroot int len; short resid; 3805171Swnj register struct ifqueue *inq; 38116511Skarels int off, s; 3824686Swnj 3835171Swnj es->es_if.if_ipackets++; 3845105Swnj 3855105Swnj /* 3865171Swnj * Purge BDP; drop if input error indicated. 3875105Swnj */ 3886335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 3896335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 3904771Swnj if (addr->en_istat&EN_IERROR) { 3915105Swnj es->es_if.if_ierrors++; 3925083Swnj goto setup; 3934686Swnj } 3945105Swnj 3955105Swnj /* 3966471Sroot * Calculate input data length. 3975105Swnj * Get pointer to ethernet header (in input buffer). 3985105Swnj * Deal with trailer protocol: if type is PUP trailer 3995105Swnj * get true type from first 16-bit word past data. 4005105Swnj * Remember that type was trailer by setting off. 4015105Swnj */ 4026471Sroot resid = addr->en_iwc; 4036471Sroot if (resid) 4046471Sroot resid |= 0176000; 4056925Swnj len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1; 4066471Sroot len -= sizeof (struct en_header); 4076925Swnj if (len > ENMRU) 4086471Sroot goto setup; /* sanity */ 4095105Swnj en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 41012352Ssam en->en_type = ntohs(en->en_type); 4115083Swnj #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 41212352Ssam if (en->en_type >= ENTYPE_TRAIL && 41312352Ssam en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) { 41412352Ssam off = (en->en_type - ENTYPE_TRAIL) * 512; 4156925Swnj if (off > ENMTU) 4165171Swnj goto setup; /* sanity */ 41712352Ssam en->en_type = ntohs(*endataaddr(en, off, u_short *)); 41812352Ssam resid = ntohs(*(endataaddr(en, off+2, u_short *))); 4196471Sroot if (off + resid > len) 4206471Sroot goto setup; /* sanity */ 4216471Sroot len = off + resid; 4225083Swnj } else 4235083Swnj off = 0; 4245083Swnj if (len == 0) 4255083Swnj goto setup; 42613293Ssam #ifdef ENF_SWABIPS 42713293Ssam if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP) 42813293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len); 42913293Ssam #endif 4305105Swnj /* 4315105Swnj * Pull packet off interface. Off is nonzero if packet 4325105Swnj * has trailing header; if_rubaget will then force this header 4335105Swnj * information to be at the front, but we still have to drop 4346471Sroot * the type and length which are at the front of any trailer data. 4355105Swnj */ 436*24790Skarels m = if_rubaget(&es->es_ifuba, len, off, &es->es_if); 4375213Swnj if (m == 0) 4385213Swnj goto setup; 4395105Swnj if (off) { 440*24790Skarels struct ifnet *ifp; 441*24790Skarels 442*24790Skarels ifp = *(mtod(m, struct ifnet **)); 4436471Sroot m->m_off += 2 * sizeof (u_short); 4446471Sroot m->m_len -= 2 * sizeof (u_short); 445*24790Skarels *(mtod(m, struct ifnet **)) = ifp; 4465105Swnj } 4476027Ssam switch (en->en_type) { 4486027Ssam 4496027Ssam #ifdef INET 45012352Ssam case ENTYPE_IP: 4516260Swnj schednetisr(NETISR_IP); 4526027Ssam inq = &ipintrq; 4536027Ssam break; 4546027Ssam #endif 4556335Ssam #ifdef PUP 45613458Ssam case ENTYPE_PUP: 45713458Ssam rpup_input(m); 4586027Ssam goto setup; 4596335Ssam #endif 4606476Swnj default: 46113458Ssam #ifdef notdef 46213458Ssam enproto.sp_protocol = en->en_type; 46313458Ssam endst.sen_host = en->en_dhost; 46413458Ssam endst.sen_net = ensrc.sen_net = es->es_if.if_net; 46513458Ssam ensrc.sen_host = en->en_shost; 46613458Ssam raw_input(m, &enproto, 46713458Ssam (struct sockaddr *)&ensrc, (struct sockaddr *)&endst); 46813458Ssam #else 4696476Swnj m_freem(m); 47013458Ssam #endif 4716476Swnj goto setup; 4726335Ssam } 4736335Ssam 47416511Skarels s = splimp(); 4756207Swnj if (IF_QFULL(inq)) { 4766207Swnj IF_DROP(inq); 4776335Ssam m_freem(m); 4786207Swnj } else 4796207Swnj IF_ENQUEUE(inq, m); 48016511Skarels splx(s); 4815105Swnj 4824688Swnj setup: 4835105Swnj /* 4845105Swnj * Reset for next packet. 4855105Swnj */ 4865105Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 4876925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 4884771Swnj addr->en_istat = EN_IEN|EN_GO; 4894688Swnj } 4904686Swnj 4915083Swnj /* 4925083Swnj * Ethernet output routine. 4935083Swnj * Encapsulate a packet of type family for the local net. 4945105Swnj * Use trailer local net encapsulation if enough data in first 4955105Swnj * packet leaves a multiple of 512 bytes of data in remainder. 4965083Swnj */ 4976335Ssam enoutput(ifp, m0, dst) 4985083Swnj struct ifnet *ifp; 4995083Swnj struct mbuf *m0; 5006335Ssam struct sockaddr *dst; 5014686Swnj { 5026503Ssam int type, dest, s, error; 5035105Swnj register struct mbuf *m = m0; 5045083Swnj register struct en_header *en; 5056335Ssam register int off; 5064686Swnj 5076335Ssam switch (dst->sa_family) { 5085083Swnj 5095083Swnj #ifdef INET 5106335Ssam case AF_INET: 51119864Skarels { 51219864Skarels struct in_addr in; 51319864Skarels 51419864Skarels in = ((struct sockaddr_in *)dst)->sin_addr; 51519864Skarels if (in_broadcast(in)) 51619864Skarels dest = EN_BROADCAST; 51719864Skarels else 51819864Skarels dest = in_lnaof(in); 51919864Skarels } 52019864Skarels if (dest >= 0x100) { 5216503Ssam error = EPERM; /* ??? */ 5226486Swnj goto bad; 5236503Ssam } 5246335Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 52513054Ssam /* need per host negotiation */ 52613054Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 5276335Ssam if (off > 0 && (off & 0x1ff) == 0 && 5286471Sroot m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 52912352Ssam type = ENTYPE_TRAIL + (off>>9); 5306471Sroot m->m_off -= 2 * sizeof (u_short); 5316471Sroot m->m_len += 2 * sizeof (u_short); 53212352Ssam *mtod(m, u_short *) = htons((u_short)ENTYPE_IP); 53312352Ssam *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); 5345105Swnj goto gottrailertype; 5355083Swnj } 53612352Ssam type = ENTYPE_IP; 5375105Swnj off = 0; 5385105Swnj goto gottype; 5395083Swnj #endif 5406027Ssam #ifdef PUP 5416335Ssam case AF_PUP: 54212833Ssam dest = ((struct sockaddr_pup *)dst)->spup_host; 54312352Ssam type = ENTYPE_PUP; 5446027Ssam off = 0; 5456027Ssam goto gottype; 5466027Ssam #endif 5476027Ssam 54813458Ssam #ifdef notdef 54913458Ssam case AF_ETHERLINK: 55013458Ssam goto gotheader; 55113458Ssam #endif 55213458Ssam 5535083Swnj default: 5546335Ssam printf("en%d: can't handle af%d\n", ifp->if_unit, 5556335Ssam dst->sa_family); 5566503Ssam error = EAFNOSUPPORT; 5576503Ssam goto bad; 5584686Swnj } 5595105Swnj 5605171Swnj gottrailertype: 5615105Swnj /* 5625105Swnj * Packet to be sent as trailer: move first packet 5635105Swnj * (control information) to end of chain. 5645105Swnj */ 5655105Swnj while (m->m_next) 5665105Swnj m = m->m_next; 5675105Swnj m->m_next = m0; 5685105Swnj m = m0->m_next; 5695105Swnj m0->m_next = 0; 5705171Swnj m0 = m; 5715105Swnj 5725171Swnj gottype: 5735105Swnj /* 5745105Swnj * Add local net header. If no space in first mbuf, 5755105Swnj * allocate another. 5765105Swnj */ 5775213Swnj if (m->m_off > MMAXOFF || 5785213Swnj MMINOFF + sizeof (struct en_header) > m->m_off) { 57917559Skarels MGET(m, M_DONTWAIT, MT_HEADER); 5805083Swnj if (m == 0) { 5816503Ssam error = ENOBUFS; 5826503Ssam goto bad; 5835083Swnj } 5845083Swnj m->m_next = m0; 5855083Swnj m->m_off = MMINOFF; 5865083Swnj m->m_len = sizeof (struct en_header); 5875083Swnj } else { 5885083Swnj m->m_off -= sizeof (struct en_header); 5895083Swnj m->m_len += sizeof (struct en_header); 5905083Swnj } 5915083Swnj en = mtod(m, struct en_header *); 59216380Skarels /* add en_shost later */ 5935083Swnj en->en_dhost = dest; 59412352Ssam en->en_type = htons((u_short)type); 5955105Swnj 596*24790Skarels #ifdef notdef 59713458Ssam gotheader: 598*24790Skarels #endif 5995105Swnj /* 6005105Swnj * Queue message on interface, and start output if interface 6015105Swnj * not yet active. 6025105Swnj */ 6035083Swnj s = splimp(); 6046207Swnj if (IF_QFULL(&ifp->if_snd)) { 6056207Swnj IF_DROP(&ifp->if_snd); 6066503Ssam error = ENOBUFS; 6076503Ssam goto qfull; 6086207Swnj } 6095083Swnj IF_ENQUEUE(&ifp->if_snd, m); 6105083Swnj if (en_softc[ifp->if_unit].es_oactive == 0) 6115083Swnj enstart(ifp->if_unit); 6125275Swnj splx(s); 6136503Ssam return (0); 6146503Ssam qfull: 6156503Ssam m0 = m; 6166503Ssam splx(s); 6176484Swnj bad: 6186503Ssam m_freem(m0); 6196503Ssam return (error); 6204686Swnj } 62113054Ssam 62213054Ssam /* 62313054Ssam * Process an ioctl request. 62413054Ssam */ 62513054Ssam enioctl(ifp, cmd, data) 62613054Ssam register struct ifnet *ifp; 62713054Ssam int cmd; 62813054Ssam caddr_t data; 62913054Ssam { 63019864Skarels register struct en_softc *es = ((struct en_softc *)ifp); 63119864Skarels struct ifaddr *ifa = (struct ifaddr *) data; 63213054Ssam int s = splimp(), error = 0; 63319864Skarels struct endevice *enaddr; 63413054Ssam 63513054Ssam switch (cmd) { 63613054Ssam 63713054Ssam case SIOCSIFADDR: 63819864Skarels enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr; 63919864Skarels es->es_host = (~enaddr->en_addr) & 0xff; 64019864Skarels /* 64119864Skarels * Attempt to check agreement of protocol address 64219864Skarels * and board address. 64319864Skarels */ 64419864Skarels switch (ifa->ifa_addr.sa_family) { 64519864Skarels case AF_INET: 64619864Skarels if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host) 64719864Skarels return (EADDRNOTAVAIL); 64819864Skarels break; 64919864Skarels } 65019864Skarels ifp->if_flags |= IFF_UP; 65119864Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 65213054Ssam eninit(ifp->if_unit); 65313054Ssam break; 65413054Ssam 65513054Ssam default: 65613054Ssam error = EINVAL; 657*24790Skarels break; 65813054Ssam } 65913054Ssam splx(s); 66013054Ssam return (error); 66113054Ssam } 66213054Ssam 66313293Ssam #ifdef ENF_SWABIPS 66413293Ssam /* 66513293Ssam * Swab bytes 66613293Ssam * Jeffrey Mogul, Stanford 66713293Ssam */ 66813293Ssam enswab(from, to, n) 66919864Skarels register unsigned char *from, *to; 67013293Ssam register int n; 67113293Ssam { 67213293Ssam register unsigned long temp; 67319864Skarels 67419864Skarels if ((n <= 0) || (n > 0xFFFF)) { 67519864Skarels printf("enswab: bad len %d\n", n); 67619864Skarels return; 67719864Skarels } 67813293Ssam 67913293Ssam n >>= 1; n++; 68019864Skarels #define STEP {temp = *from++;*to++ = *from++;*to++ = temp;} 68113293Ssam /* round to multiple of 8 */ 68213293Ssam while ((--n) & 07) 68313293Ssam STEP; 68413293Ssam n >>= 3; 68513293Ssam while (--n >= 0) { 68613293Ssam STEP; STEP; STEP; STEP; 68713293Ssam STEP; STEP; STEP; STEP; 68813293Ssam } 68913293Ssam } 69013293Ssam #endif 691