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*25272Sbloom * @(#)if_en.c 6.10 (Berkeley) 10/24/85 723290Smckusick */ 84686Swnj 94686Swnj #include "en.h" 10*25272Sbloom #if NEN > 0 115105Swnj 124686Swnj /* 135105Swnj * Xerox prototype (3 Mb) Ethernet interface driver. 144686Swnj */ 159796Ssam #include "../machine/pte.h" 164686Swnj 1717113Sbloom #include "param.h" 1817113Sbloom #include "systm.h" 1917113Sbloom #include "mbuf.h" 2017113Sbloom #include "buf.h" 2117113Sbloom #include "protosw.h" 2217113Sbloom #include "socket.h" 2317113Sbloom #include "vmmac.h" 2417113Sbloom #include "errno.h" 2517113Sbloom #include "ioctl.h" 268462Sroot 278462Sroot #include "../net/if.h" 288462Sroot #include "../net/netisr.h" 298462Sroot #include "../net/route.h" 3024790Skarels 3124790Skarels #ifdef BBNNET 3224790Skarels #define INET 3324790Skarels #endif 3424790Skarels #ifdef INET 358418Swnj #include "../netinet/in.h" 368418Swnj #include "../netinet/in_systm.h" 3719864Skarels #include "../netinet/in_var.h" 388418Swnj #include "../netinet/ip.h" 3924790Skarels #endif 4024790Skarels 4119950Sbloom #ifdef PUP 428418Swnj #include "../netpup/pup.h" 4313458Ssam #include "../netpup/ether.h" 4419950Sbloom #endif 454686Swnj 468462Sroot #include "../vax/cpu.h" 478462Sroot #include "../vax/mtpr.h" 4817113Sbloom #include "if_en.h" 4917113Sbloom #include "if_enreg.h" 5017113Sbloom #include "if_uba.h" 518462Sroot #include "../vaxuba/ubareg.h" 528462Sroot #include "../vaxuba/ubavar.h" 538462Sroot 545213Swnj #define ENMTU (1024+512) 556925Swnj #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */ 565083Swnj 574686Swnj int enprobe(), enattach(), enrint(), enxint(), encollide(); 584686Swnj struct uba_device *eninfo[NEN]; 594686Swnj u_short enstd[] = { 0 }; 604686Swnj struct uba_driver endriver = 615171Swnj { enprobe, 0, enattach, 0, enstd, "en", eninfo }; 624686Swnj #define ENUNIT(x) minor(x) 634686Swnj 6413054Ssam int eninit(),enoutput(),enreset(),enioctl(); 655105Swnj 6613293Ssam #ifdef notdef 675105Swnj /* 6813293Ssam * If you need to byte swap IP's in the system, define 6913293Ssam * this and do a SIOCSIFFLAGS at boot time. 7013293Ssam */ 7119864Skarels #define ENF_SWABIPS 0x1000 7213293Ssam #endif 7313293Ssam 7413293Ssam /* 755105Swnj * Ethernet software status per interface. 765105Swnj * 775105Swnj * Each interface is referenced by a network interface structure, 785105Swnj * es_if, which the routing code uses to locate the interface. 795105Swnj * This structure contains the output queue for the interface, its address, ... 805105Swnj * We also have, for each interface, a UBA interface structure, which 815105Swnj * contains information about the UNIBUS resources held by the interface: 825105Swnj * map registers, buffered data paths, etc. Information is cached in this 835105Swnj * structure for use by the if_uba.c routines in running the interface 845105Swnj * efficiently. 855105Swnj */ 865083Swnj struct en_softc { 875105Swnj struct ifnet es_if; /* network-visible interface */ 885105Swnj struct ifuba es_ifuba; /* UNIBUS resources */ 8916380Skarels short es_host; /* hardware host number */ 905105Swnj short es_delay; /* current output delay */ 915105Swnj short es_mask; /* mask for current output delay */ 926471Sroot short es_lastx; /* host last transmitted to */ 935105Swnj short es_oactive; /* is output active? */ 945105Swnj short es_olen; /* length of last output */ 955083Swnj } en_softc[NEN]; 964686Swnj 975105Swnj /* 985105Swnj * Do output DMA to determine interface presence and 995105Swnj * interrupt vector. DMA is too short to disturb other hosts. 1005105Swnj */ 1014686Swnj enprobe(reg) 1024686Swnj caddr_t reg; 1034686Swnj { 1045171Swnj register int br, cvec; /* r11, r10 value-result */ 1054686Swnj register struct endevice *addr = (struct endevice *)reg; 1064686Swnj 1074686Swnj #ifdef lint 1084686Swnj br = 0; cvec = br; br = cvec; 1094922Swnj enrint(0); enxint(0); encollide(0); 1104686Swnj #endif 1114686Swnj addr->en_istat = 0; 1124686Swnj addr->en_owc = -1; 1134686Swnj addr->en_oba = 0; 1144771Swnj addr->en_ostat = EN_IEN|EN_GO; 1154686Swnj DELAY(100000); 1164686Swnj addr->en_ostat = 0; 1174686Swnj return (1); 1184686Swnj } 1194686Swnj 1205105Swnj /* 1215105Swnj * Interface exists: make available by filling in network interface 1225105Swnj * record. System will initialize the interface when it is ready 1235105Swnj * to accept packets. 1245105Swnj */ 1254686Swnj enattach(ui) 1264686Swnj struct uba_device *ui; 1274686Swnj { 1285105Swnj register struct en_softc *es = &en_softc[ui->ui_unit]; 1294688Swnj 1305105Swnj es->es_if.if_unit = ui->ui_unit; 1315171Swnj es->es_if.if_name = "en"; 1325105Swnj es->es_if.if_mtu = ENMTU; 13319864Skarels es->es_if.if_flags = IFF_BROADCAST; 1345171Swnj es->es_if.if_init = eninit; 1355105Swnj es->es_if.if_output = enoutput; 13613054Ssam es->es_if.if_ioctl = enioctl; 1378978Sroot es->es_if.if_reset = enreset; 1386554Ssam es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT; 1399271Ssam #if defined(VAX750) 1409271Ssam /* don't chew up 750 bdp's */ 1419271Ssam if (cpu == VAX_750 && ui->ui_unit > 0) 1429271Ssam es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP; 1439271Ssam #endif 1445160Swnj if_attach(&es->es_if); 1454686Swnj } 1464686Swnj 1475105Swnj /* 1485105Swnj * Reset of interface after UNIBUS reset. 1495105Swnj * If interface is on specified uba, reset its state. 1505105Swnj */ 1515105Swnj enreset(unit, uban) 1525105Swnj int unit, uban; 1535105Swnj { 1545105Swnj register struct uba_device *ui; 1555105Swnj 1565171Swnj if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || 1575171Swnj ui->ui_ubanum != uban) 1585105Swnj return; 1595171Swnj printf(" en%d", unit); 1605105Swnj eninit(unit); 1615105Swnj } 1625105Swnj 1635105Swnj /* 1645105Swnj * Initialization of interface; clear recorded pending 1655105Swnj * operations, and reinitialize UNIBUS usage. 1665105Swnj */ 1674688Swnj eninit(unit) 1684686Swnj int unit; 1695083Swnj { 1705171Swnj register struct en_softc *es = &en_softc[unit]; 1715171Swnj register struct uba_device *ui = eninfo[unit]; 1724686Swnj register struct endevice *addr; 17313054Ssam int s; 1744686Swnj 17519864Skarels if (es->es_if.if_addrlist == (struct ifaddr *)0) 17612349Ssam return; 1775105Swnj if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 1786925Swnj sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 1795171Swnj printf("en%d: can't initialize\n", unit); 1806335Ssam es->es_if.if_flags &= ~IFF_UP; 1815083Swnj return; 1824686Swnj } 1834686Swnj addr = (struct endevice *)ui->ui_addr; 1845083Swnj addr->en_istat = addr->en_ostat = 0; 1854686Swnj 1865105Swnj /* 1875171Swnj * Hang a receive and start any 1885171Swnj * pending writes by faking a transmit complete. 1895105Swnj */ 1905105Swnj s = splimp(); 1915171Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 1926925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 1935171Swnj addr->en_istat = EN_IEN|EN_GO; 1945171Swnj es->es_oactive = 1; 19519864Skarels es->es_if.if_flags |= IFF_RUNNING; 1965105Swnj enxint(unit); 1975105Swnj splx(s); 1984686Swnj } 1994686Swnj 2006471Sroot int enalldelay = 0; 2016951Swnj int enlastdel = 50; 2026471Sroot int enlastmask = (~0) << 5; 2035083Swnj 2045105Swnj /* 2055105Swnj * Start or restart output on interface. 2065105Swnj * If interface is already active, then this is a retransmit 2075105Swnj * after a collision, and just restuff registers and delay. 2085105Swnj * If interface is not already active, get another datagram 2095105Swnj * to send off of the interface queue, and map it to the interface 2105105Swnj * before starting the output. 2115105Swnj */ 2124688Swnj enstart(dev) 2134686Swnj dev_t dev; 2144686Swnj { 2155171Swnj int unit = ENUNIT(dev); 2165171Swnj struct uba_device *ui = eninfo[unit]; 2175171Swnj register struct en_softc *es = &en_softc[unit]; 2185083Swnj register struct endevice *addr; 21916380Skarels register struct en_header *en; 2205083Swnj struct mbuf *m; 2215083Swnj int dest; 2224686Swnj 2235083Swnj if (es->es_oactive) 2245083Swnj goto restart; 2255105Swnj 2265105Swnj /* 2275105Swnj * Not already active: dequeue another request 2285105Swnj * and map it to the UNIBUS. If no more requests, 2295105Swnj * just return. 2305105Swnj */ 2315105Swnj IF_DEQUEUE(&es->es_if.if_snd, m); 2325083Swnj if (m == 0) { 2335083Swnj es->es_oactive = 0; 2344686Swnj return; 2354686Swnj } 23616380Skarels en = mtod(m, struct en_header *); 23716380Skarels dest = en->en_dhost; 23816380Skarels en->en_shost = es->es_host; 2395105Swnj es->es_olen = if_wubaput(&es->es_ifuba, m); 24013293Ssam #ifdef ENF_SWABIPS 24113293Ssam /* 24213293Ssam * The Xerox interface does word at a time DMA, so 24313293Ssam * someone must do byte swapping of user data if high 24413293Ssam * and low ender machines are to communicate. It doesn't 24513293Ssam * belong here, but certain people depend on it, so... 24613293Ssam * 24713293Ssam * Should swab everybody, but this is a kludge anyway. 24813293Ssam */ 24913293Ssam if (es->es_if.if_flags & ENF_SWABIPS) { 25013293Ssam en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr; 25113293Ssam if (en->en_type == ENTYPE_IP) 25213293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), 25313293Ssam es->es_olen - sizeof (struct en_header) + 1); 25413293Ssam } 25513293Ssam #endif 25613293Ssam 2575105Swnj /* 2585105Swnj * Ethernet cannot take back-to-back packets (no 2596471Sroot * buffering in interface. To help avoid overrunning 2606471Sroot * receivers, enforce a small delay (about 1ms) in interface: 2616471Sroot * * between all packets when enalldelay 2626471Sroot * * whenever last packet was broadcast 2636471Sroot * * whenever this packet is to same host as last packet 2645105Swnj */ 2656471Sroot if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 2665083Swnj es->es_delay = enlastdel; 2676471Sroot es->es_mask = enlastmask; 2686471Sroot } 2696471Sroot es->es_lastx = dest; 2705105Swnj 2715083Swnj restart: 2725105Swnj /* 2735105Swnj * Have request mapped to UNIBUS for transmission. 2745105Swnj * Purge any stale data from this BDP, and start the otput. 2755105Swnj */ 2766335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 2776335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 2784686Swnj addr = (struct endevice *)ui->ui_addr; 2795160Swnj addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 2805083Swnj addr->en_odelay = es->es_delay; 2815083Swnj addr->en_owc = -((es->es_olen + 1) >> 1); 2824771Swnj addr->en_ostat = EN_IEN|EN_GO; 2835083Swnj es->es_oactive = 1; 2844686Swnj } 2854686Swnj 2865105Swnj /* 2875105Swnj * Ethernet interface transmitter interrupt. 2885105Swnj * Start another output if more data to send. 2895105Swnj */ 2904686Swnj enxint(unit) 2914686Swnj int unit; 2924686Swnj { 2935171Swnj register struct uba_device *ui = eninfo[unit]; 2945171Swnj register struct en_softc *es = &en_softc[unit]; 2956242Sroot register struct endevice *addr = (struct endevice *)ui->ui_addr; 2964686Swnj 2975083Swnj if (es->es_oactive == 0) 2985083Swnj return; 2996242Sroot if (es->es_mask && (addr->en_ostat&EN_OERROR)) { 3006242Sroot es->es_if.if_oerrors++; 3016242Sroot endocoll(unit); 3026242Sroot return; 3036242Sroot } 3045171Swnj es->es_if.if_opackets++; 3055083Swnj es->es_oactive = 0; 3065083Swnj es->es_delay = 0; 3075083Swnj es->es_mask = ~0; 3085696Sroot if (es->es_ifuba.ifu_xtofree) { 3095696Sroot m_freem(es->es_ifuba.ifu_xtofree); 3105696Sroot es->es_ifuba.ifu_xtofree = 0; 3115696Sroot } 3125105Swnj if (es->es_if.if_snd.ifq_head == 0) { 3136471Sroot es->es_lastx = 256; /* putatively illegal */ 3144686Swnj return; 3154686Swnj } 3165083Swnj enstart(unit); 3174686Swnj } 3184686Swnj 3195105Swnj /* 3205105Swnj * Collision on ethernet interface. Do exponential 3215105Swnj * backoff, and retransmit. If have backed off all 3226335Ssam * the way print warning diagnostic, and drop packet. 3235105Swnj */ 3244686Swnj encollide(unit) 3254686Swnj int unit; 3264686Swnj { 3276242Sroot struct en_softc *es = &en_softc[unit]; 3284686Swnj 3295105Swnj es->es_if.if_collisions++; 3305083Swnj if (es->es_oactive == 0) 3314686Swnj return; 3326242Sroot endocoll(unit); 3336242Sroot } 3346242Sroot 3356242Sroot endocoll(unit) 3366242Sroot int unit; 3376242Sroot { 3386242Sroot register struct en_softc *es = &en_softc[unit]; 3396242Sroot 3405171Swnj /* 3415171Swnj * Es_mask is a 16 bit number with n low zero bits, with 3425171Swnj * n the number of backoffs. When es_mask is 0 we have 3435171Swnj * backed off 16 times, and give up. 3445171Swnj */ 3455083Swnj if (es->es_mask == 0) { 3465213Swnj printf("en%d: send error\n", unit); 3475083Swnj enxint(unit); 3485171Swnj return; 3494686Swnj } 3505171Swnj /* 3515171Swnj * Another backoff. Restart with delay based on n low bits 3525171Swnj * of the interval timer. 3535171Swnj */ 3545171Swnj es->es_mask <<= 1; 3555171Swnj es->es_delay = mfpr(ICR) &~ es->es_mask; 3565171Swnj enstart(unit); 3574686Swnj } 3584686Swnj 35913458Ssam #ifdef notdef 36013458Ssam struct sockproto enproto = { AF_ETHERLINK }; 36113458Ssam struct sockaddr_en endst = { AF_ETHERLINK }; 36213458Ssam struct sockaddr_en ensrc = { AF_ETHERLINK }; 36313458Ssam #endif 3645105Swnj /* 3655105Swnj * Ethernet interface receiver interrupt. 3665105Swnj * If input error just drop packet. 3675105Swnj * Otherwise purge input buffered data path and examine 3685105Swnj * packet to determine type. If can't determine length 3695105Swnj * from type, then have to drop packet. Othewise decapsulate 3705105Swnj * packet based on type and pass to type specific higher-level 3715105Swnj * input routine. 3725105Swnj */ 3734686Swnj enrint(unit) 3744686Swnj int unit; 3754686Swnj { 3765171Swnj register struct en_softc *es = &en_softc[unit]; 3775171Swnj struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; 3785171Swnj register struct en_header *en; 3795083Swnj struct mbuf *m; 3808603Sroot int len; short resid; 3815171Swnj register struct ifqueue *inq; 38216511Skarels int off, s; 3834686Swnj 3845171Swnj es->es_if.if_ipackets++; 3855105Swnj 3865105Swnj /* 3875171Swnj * Purge BDP; drop if input error indicated. 3885105Swnj */ 3896335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 3906335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 3914771Swnj if (addr->en_istat&EN_IERROR) { 3925105Swnj es->es_if.if_ierrors++; 3935083Swnj goto setup; 3944686Swnj } 3955105Swnj 3965105Swnj /* 3976471Sroot * Calculate input data length. 3985105Swnj * Get pointer to ethernet header (in input buffer). 3995105Swnj * Deal with trailer protocol: if type is PUP trailer 4005105Swnj * get true type from first 16-bit word past data. 4015105Swnj * Remember that type was trailer by setting off. 4025105Swnj */ 4036471Sroot resid = addr->en_iwc; 4046471Sroot if (resid) 4056471Sroot resid |= 0176000; 4066925Swnj len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1; 4076471Sroot len -= sizeof (struct en_header); 4086925Swnj if (len > ENMRU) 4096471Sroot goto setup; /* sanity */ 4105105Swnj en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 41112352Ssam en->en_type = ntohs(en->en_type); 4125083Swnj #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 41312352Ssam if (en->en_type >= ENTYPE_TRAIL && 41412352Ssam en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) { 41512352Ssam off = (en->en_type - ENTYPE_TRAIL) * 512; 4166925Swnj if (off > ENMTU) 4175171Swnj goto setup; /* sanity */ 41812352Ssam en->en_type = ntohs(*endataaddr(en, off, u_short *)); 41912352Ssam resid = ntohs(*(endataaddr(en, off+2, u_short *))); 4206471Sroot if (off + resid > len) 4216471Sroot goto setup; /* sanity */ 4226471Sroot len = off + resid; 4235083Swnj } else 4245083Swnj off = 0; 4255083Swnj if (len == 0) 4265083Swnj goto setup; 42713293Ssam #ifdef ENF_SWABIPS 42813293Ssam if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP) 42913293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len); 43013293Ssam #endif 4315105Swnj /* 4325105Swnj * Pull packet off interface. Off is nonzero if packet 4335105Swnj * has trailing header; if_rubaget will then force this header 4345105Swnj * information to be at the front, but we still have to drop 4356471Sroot * the type and length which are at the front of any trailer data. 4365105Swnj */ 43724790Skarels m = if_rubaget(&es->es_ifuba, len, off, &es->es_if); 4385213Swnj if (m == 0) 4395213Swnj goto setup; 4405105Swnj if (off) { 44124790Skarels struct ifnet *ifp; 44224790Skarels 44324790Skarels ifp = *(mtod(m, struct ifnet **)); 4446471Sroot m->m_off += 2 * sizeof (u_short); 4456471Sroot m->m_len -= 2 * sizeof (u_short); 44624790Skarels *(mtod(m, struct ifnet **)) = ifp; 4475105Swnj } 4486027Ssam switch (en->en_type) { 4496027Ssam 4506027Ssam #ifdef INET 45112352Ssam case ENTYPE_IP: 4526260Swnj schednetisr(NETISR_IP); 4536027Ssam inq = &ipintrq; 4546027Ssam break; 4556027Ssam #endif 4566335Ssam #ifdef PUP 45713458Ssam case ENTYPE_PUP: 45813458Ssam rpup_input(m); 4596027Ssam goto setup; 4606335Ssam #endif 4616476Swnj default: 46213458Ssam #ifdef notdef 46313458Ssam enproto.sp_protocol = en->en_type; 46413458Ssam endst.sen_host = en->en_dhost; 46513458Ssam endst.sen_net = ensrc.sen_net = es->es_if.if_net; 46613458Ssam ensrc.sen_host = en->en_shost; 46713458Ssam raw_input(m, &enproto, 46813458Ssam (struct sockaddr *)&ensrc, (struct sockaddr *)&endst); 46913458Ssam #else 4706476Swnj m_freem(m); 47113458Ssam #endif 4726476Swnj goto setup; 4736335Ssam } 4746335Ssam 47516511Skarels s = splimp(); 4766207Swnj if (IF_QFULL(inq)) { 4776207Swnj IF_DROP(inq); 4786335Ssam m_freem(m); 4796207Swnj } else 4806207Swnj IF_ENQUEUE(inq, m); 48116511Skarels splx(s); 4825105Swnj 4834688Swnj setup: 4845105Swnj /* 4855105Swnj * Reset for next packet. 4865105Swnj */ 4875105Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 4886925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 4894771Swnj addr->en_istat = EN_IEN|EN_GO; 4904688Swnj } 4914686Swnj 4925083Swnj /* 4935083Swnj * Ethernet output routine. 4945083Swnj * Encapsulate a packet of type family for the local net. 4955105Swnj * Use trailer local net encapsulation if enough data in first 4965105Swnj * packet leaves a multiple of 512 bytes of data in remainder. 4975083Swnj */ 4986335Ssam enoutput(ifp, m0, dst) 4995083Swnj struct ifnet *ifp; 5005083Swnj struct mbuf *m0; 5016335Ssam struct sockaddr *dst; 5024686Swnj { 5036503Ssam int type, dest, s, error; 5045105Swnj register struct mbuf *m = m0; 5055083Swnj register struct en_header *en; 5066335Ssam register int off; 5074686Swnj 5086335Ssam switch (dst->sa_family) { 5095083Swnj 5105083Swnj #ifdef INET 5116335Ssam case AF_INET: 51219864Skarels { 51319864Skarels struct in_addr in; 51419864Skarels 51519864Skarels in = ((struct sockaddr_in *)dst)->sin_addr; 51619864Skarels if (in_broadcast(in)) 51719864Skarels dest = EN_BROADCAST; 51819864Skarels else 51919864Skarels dest = in_lnaof(in); 52019864Skarels } 52119864Skarels if (dest >= 0x100) { 5226503Ssam error = EPERM; /* ??? */ 5236486Swnj goto bad; 5246503Ssam } 5256335Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 52613054Ssam /* need per host negotiation */ 52713054Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 5286335Ssam if (off > 0 && (off & 0x1ff) == 0 && 5296471Sroot m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 53012352Ssam type = ENTYPE_TRAIL + (off>>9); 5316471Sroot m->m_off -= 2 * sizeof (u_short); 5326471Sroot m->m_len += 2 * sizeof (u_short); 53312352Ssam *mtod(m, u_short *) = htons((u_short)ENTYPE_IP); 53412352Ssam *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); 5355105Swnj goto gottrailertype; 5365083Swnj } 53712352Ssam type = ENTYPE_IP; 5385105Swnj off = 0; 5395105Swnj goto gottype; 5405083Swnj #endif 5416027Ssam #ifdef PUP 5426335Ssam case AF_PUP: 54312833Ssam dest = ((struct sockaddr_pup *)dst)->spup_host; 54412352Ssam type = ENTYPE_PUP; 5456027Ssam off = 0; 5466027Ssam goto gottype; 5476027Ssam #endif 5486027Ssam 54913458Ssam #ifdef notdef 55013458Ssam case AF_ETHERLINK: 55113458Ssam goto gotheader; 55213458Ssam #endif 55313458Ssam 5545083Swnj default: 5556335Ssam printf("en%d: can't handle af%d\n", ifp->if_unit, 5566335Ssam dst->sa_family); 5576503Ssam error = EAFNOSUPPORT; 5586503Ssam goto bad; 5594686Swnj } 5605105Swnj 5615171Swnj gottrailertype: 5625105Swnj /* 5635105Swnj * Packet to be sent as trailer: move first packet 5645105Swnj * (control information) to end of chain. 5655105Swnj */ 5665105Swnj while (m->m_next) 5675105Swnj m = m->m_next; 5685105Swnj m->m_next = m0; 5695105Swnj m = m0->m_next; 5705105Swnj m0->m_next = 0; 5715171Swnj m0 = m; 5725105Swnj 5735171Swnj gottype: 5745105Swnj /* 5755105Swnj * Add local net header. If no space in first mbuf, 5765105Swnj * allocate another. 5775105Swnj */ 5785213Swnj if (m->m_off > MMAXOFF || 5795213Swnj MMINOFF + sizeof (struct en_header) > m->m_off) { 58017559Skarels MGET(m, M_DONTWAIT, MT_HEADER); 5815083Swnj if (m == 0) { 5826503Ssam error = ENOBUFS; 5836503Ssam goto bad; 5845083Swnj } 5855083Swnj m->m_next = m0; 5865083Swnj m->m_off = MMINOFF; 5875083Swnj m->m_len = sizeof (struct en_header); 5885083Swnj } else { 5895083Swnj m->m_off -= sizeof (struct en_header); 5905083Swnj m->m_len += sizeof (struct en_header); 5915083Swnj } 5925083Swnj en = mtod(m, struct en_header *); 59316380Skarels /* add en_shost later */ 5945083Swnj en->en_dhost = dest; 59512352Ssam en->en_type = htons((u_short)type); 5965105Swnj 59724790Skarels #ifdef notdef 59813458Ssam gotheader: 59924790Skarels #endif 6005105Swnj /* 6015105Swnj * Queue message on interface, and start output if interface 6025105Swnj * not yet active. 6035105Swnj */ 6045083Swnj s = splimp(); 6056207Swnj if (IF_QFULL(&ifp->if_snd)) { 6066207Swnj IF_DROP(&ifp->if_snd); 6076503Ssam error = ENOBUFS; 6086503Ssam goto qfull; 6096207Swnj } 6105083Swnj IF_ENQUEUE(&ifp->if_snd, m); 6115083Swnj if (en_softc[ifp->if_unit].es_oactive == 0) 6125083Swnj enstart(ifp->if_unit); 6135275Swnj splx(s); 6146503Ssam return (0); 6156503Ssam qfull: 6166503Ssam m0 = m; 6176503Ssam splx(s); 6186484Swnj bad: 6196503Ssam m_freem(m0); 6206503Ssam return (error); 6214686Swnj } 62213054Ssam 62313054Ssam /* 62413054Ssam * Process an ioctl request. 62513054Ssam */ 62613054Ssam enioctl(ifp, cmd, data) 62713054Ssam register struct ifnet *ifp; 62813054Ssam int cmd; 62913054Ssam caddr_t data; 63013054Ssam { 63119864Skarels register struct en_softc *es = ((struct en_softc *)ifp); 63219864Skarels struct ifaddr *ifa = (struct ifaddr *) data; 63313054Ssam int s = splimp(), error = 0; 63419864Skarels struct endevice *enaddr; 63513054Ssam 63613054Ssam switch (cmd) { 63713054Ssam 63813054Ssam case SIOCSIFADDR: 63919864Skarels enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr; 64019864Skarels es->es_host = (~enaddr->en_addr) & 0xff; 64119864Skarels /* 64219864Skarels * Attempt to check agreement of protocol address 64319864Skarels * and board address. 64419864Skarels */ 64519864Skarels switch (ifa->ifa_addr.sa_family) { 64619864Skarels case AF_INET: 64719864Skarels if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host) 64819864Skarels return (EADDRNOTAVAIL); 64919864Skarels break; 65019864Skarels } 65119864Skarels ifp->if_flags |= IFF_UP; 65219864Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 65313054Ssam eninit(ifp->if_unit); 65413054Ssam break; 65513054Ssam 65613054Ssam default: 65713054Ssam error = EINVAL; 65824790Skarels break; 65913054Ssam } 66013054Ssam splx(s); 66113054Ssam return (error); 66213054Ssam } 66313054Ssam 66413293Ssam #ifdef ENF_SWABIPS 66513293Ssam /* 66613293Ssam * Swab bytes 66713293Ssam * Jeffrey Mogul, Stanford 66813293Ssam */ 66913293Ssam enswab(from, to, n) 67019864Skarels register unsigned char *from, *to; 67113293Ssam register int n; 67213293Ssam { 67313293Ssam register unsigned long temp; 67419864Skarels 67519864Skarels if ((n <= 0) || (n > 0xFFFF)) { 67619864Skarels printf("enswab: bad len %d\n", n); 67719864Skarels return; 67819864Skarels } 67913293Ssam 68013293Ssam n >>= 1; n++; 68119864Skarels #define STEP {temp = *from++;*to++ = *from++;*to++ = temp;} 68213293Ssam /* round to multiple of 8 */ 68313293Ssam while ((--n) & 07) 68413293Ssam STEP; 68513293Ssam n >>= 3; 68613293Ssam while (--n >= 0) { 68713293Ssam STEP; STEP; STEP; STEP; 68813293Ssam STEP; STEP; STEP; STEP; 68913293Ssam } 69013293Ssam } 69113293Ssam #endif 692*25272Sbloom #endif 693