1*45432Sbostic/* 2*45432Sbostic * Copyright IBM Corporation 1987,1990 3*45432Sbostic * 4*45432Sbostic * All Rights Reserved 5*45432Sbostic * 6*45432Sbostic * Permission to use, copy, modify, and distribute this software and its 7*45432Sbostic * documentation for any purpose and without fee is hereby granted, 8*45432Sbostic * provided that the above copyright notice appear in all copies and that 9*45432Sbostic * both that copyright notice and this permission notice appear in 10*45432Sbostic * supporting documentation, and that the name of IBM not be 11*45432Sbostic * used in advertising or publicity pertaining to distribution of the 12*45432Sbostic * software without specific, written prior permission. 13*45432Sbostic * 14*45432Sbostic * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15*45432Sbostic * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR USE. 16*45432Sbostic * IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 17*45432Sbostic * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18*45432Sbostic * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19*45432Sbostic * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 20*45432Sbostic * THIS SOFTWARE. 21*45432Sbostic * 22*45432Sbostic * @(#)if_un.eg 7.1 (Berkeley) 10/29/90 23*45432Sbostic */ 24*45432Sbostic 25*45432Sbostic/* 26*45432Sbostic * Ungermann-Bass PC-NIC (Ethernet) Adapter (4.3 driver) 27*45432Sbostic */ 28*45432Sbostic 29*45432Sbostic#include "un.h" 30*45432Sbostic#if NUN > 0 31*45432Sbostic 32*45432Sbostic#include "../machine/pte.h" 33*45432Sbostic 34*45432Sbostic#include "param.h" 35*45432Sbostic#include "systm.h" 36*45432Sbostic#include "mbuf.h" 37*45432Sbostic#include "buf.h" 38*45432Sbostic#include "protosw.h" 39*45432Sbostic#include "socket.h" 40*45432Sbostic#include "vmmac.h" 41*45432Sbostic#include "ioctl.h" 42*45432Sbostic#include "errno.h" 43*45432Sbostic 44*45432Sbostic#include "../net/if.h" 45*45432Sbostic#include "../net/netisr.h" 46*45432Sbostic#include "../net/route.h" 47*45432Sbostic 48*45432Sbostic#ifdef INET 49*45432Sbostic#include "../netinet/in.h" 50*45432Sbostic#include "../netinet/in_systm.h" 51*45432Sbostic#include "../netinet/in_var.h" 52*45432Sbostic#include "../netinet/ip.h" 53*45432Sbostic#include "../netinet/if_ether.h" 54*45432Sbostic#endif INET 55*45432Sbostic 56*45432Sbostic#ifdef NS 57*45432Sbostic#include "../netns/ns.h" 58*45432Sbostic#include "../netns/ns_if.h" 59*45432Sbostic#endif NS 60*45432Sbostic 61*45432Sbostic#ifdef ISO 62*45432Sbostic#include "../netargo/if_clnp.h" 63*45432Sbostic#include "../netargo/iso.h" 64*45432Sbostic#include "../netargo/iso_var.h" 65*45432Sbostic#include "../netargo/argo_debug.h" 66*45432Sbostic#endif ISO 67*45432Sbostic 68*45432Sbostic#include "../machine/io.h" 69*45432Sbostic#include "if_unreg.h" 70*45432Sbostic#ifdef IEEELLC 71*45432Sbostic#include "if_llc.h" 72*45432Sbostic#endif IEEELLC 73*45432Sbostic#include "../machineio/ioccvar.h" 74*45432Sbostic#include "../machine/debug.h" 75*45432Sbostic 76*45432Sbosticint unprobe(), unattach(); 77*45432Sbostic 78*45432Sbostic#ifdef AT 79*45432Sbosticcaddr_t unstd[] = { (caddr_t) 0xa0000, (caddr_t) 0xa8000, 80*45432Sbostic (caddr_t) 0xb0000, (caddr_t) 0xb8000, 0 }; 81*45432Sbostic#else 82*45432Sbosticcaddr_t unstd[] = { (caddr_t) 0xf4080000, (caddr_t) 0xf4088000, 83*45432Sbostic (caddr_t) 0xf4090000, (caddr_t) 0xf4098000, 0 }; 84*45432Sbostic#endif AT 85*45432Sbostic 86*45432Sbosticstruct iocc_device *uninfo[NUN]; 87*45432Sbostic 88*45432Sbosticint unint(), uninit(), unioctl(), unoutput(), unreset(); 89*45432Sbostic 90*45432Sbosticstruct iocc_driver undriver = 91*45432Sbostic { unprobe, 0, unattach, 0, unstd, "un", uninfo, 92*45432Sbostic 0, 0, unint, UN_EADDROFF }; 93*45432Sbostic 94*45432Sbosticstruct mbuf *unget(); 95*45432Sbostic 96*45432Sbostic/* 97*45432Sbostic * Ethernet software status per adapter. 98*45432Sbostic */ 99*45432Sbosticstruct un_softc { 100*45432Sbostic struct arpcom us_ac; /* generic network interface stuff */ 101*45432Sbostic#define us_if us_ac.ac_if /* ifnet struct */ 102*45432Sbostic#define us_addr us_ac.ac_enaddr /* hardware (i.e. ethernet) address */ 103*45432Sbostic short us_oactive; /* 1 => output active */ 104*45432Sbostic short us_nextpage; /* next receive buffer page */ 105*45432Sbostic short us_xbuf; /* in-use xmt buf (if output active) */ 106*45432Sbostic short us_xfull[2]; /* 1 => a full xmt buf */ 107*45432Sbostic short us_xstart[2]; /* start address used in unstart */ 108*45432Sbostic} un_softc[NUN]; 109*45432Sbostic 110*45432Sbostic#ifdef DEBUG 111*45432Sbosticchar undebug = 0; 112*45432Sbostic#endif DEBUG 113*45432Sbostic 114*45432Sbostic#ifdef ATR 115*45432Sbostic#define move_window(window, addr) {\ 116*45432Sbostic int real_addr;\ 117*45432Sbostic int new_window;\ 118*45432Sbostic \ 119*45432Sbostic window = get_128_window();\ 120*45432Sbostic real_addr = 0xfffff & (int) addr;\ 121*45432Sbostic new_window = real_addr & 0xe0000;\ 122*45432Sbostic set_128_window(new_window);\ 123*45432Sbostic addr = (struct undevice *) (real_addr - new_window);\ 124*45432Sbostic} 125*45432Sbostic 126*45432Sbostic#define restore_window(window) set_128_window(window) 127*45432Sbostic#define bcopyin(from,to,len) bcopy((from)+pcif_128_fw,to,len) 128*45432Sbostic#define bcopyout(from,to,len) bcopy(from,(to)+pcif_128_fw,len) 129*45432Sbostic#endif ATR 130*45432Sbostic 131*45432Sbostic#ifdef IBMRTPC 132*45432Sbostic#define bcopyin bcopy 133*45432Sbostic#define bcopyout bcopy 134*45432Sbostic#endif IBMRTPC 135*45432Sbostic/* 136*45432Sbostic * unprobe - try to generate an interrupt (to see if the board is there) 137*45432Sbostic */ 138*45432Sbosticunprobe(p) 139*45432Sbostic register caddr_t p; 140*45432Sbostic{ 141*45432Sbostic register struct undevice *addr = (struct undevice *) p; 142*45432Sbostic#ifdef ATR 143*45432Sbostic register int old_window; 144*45432Sbostic move_window(old_window, addr); 145*45432Sbostic#endif ATR 146*45432Sbostic (void) unzap(addr); 147*45432Sbostic UN_GLOBIENB(0); /* global interrrupt enable */ 148*45432Sbostic MM_OUT(&addr->un_csr, UN_GSFTINT); /* generate software interrupt */ 149*45432Sbostic PROBE_DELAY(100000); 150*45432Sbostic MM_OUT(&addr->un_csr, 0); 151*45432Sbostic#ifdef ATR 152*45432Sbostic restore_window(old_window); 153*45432Sbostic#endif ATR 154*45432Sbostic return(PROBE_OK); 155*45432Sbostic} 156*45432Sbostic 157*45432Sbostic/* 158*45432Sbostic * unattach - make the interface available to the network software 159*45432Sbostic * (if the auto-configuration software determines that the interface 160*45432Sbostic * exists). The system will initialize the interface when it is 161*45432Sbostic * ready to accept packets. 162*45432Sbostic */ 163*45432Sbosticunattach(iod) 164*45432Sbostic register struct iocc_device *iod; 165*45432Sbostic{ 166*45432Sbostic register struct un_softc *us = &un_softc[iod->iod_unit]; 167*45432Sbostic register struct ifnet *ifp = &us->us_if; 168*45432Sbostic register struct undevice *addr = (struct undevice *) iod->iod_addr; 169*45432Sbostic register int i; 170*45432Sbostic#ifdef ATR 171*45432Sbostic register int old_window; 172*45432Sbostic 173*45432Sbostic move_window(old_window, addr); 174*45432Sbostic#endif ATR 175*45432Sbostic ifp->if_unit = iod->iod_unit; 176*45432Sbostic ifp->if_name = "un"; 177*45432Sbostic 178*45432Sbostic#ifdef IEEELLC 179*45432Sbostic ifp->if_mtu = ETHERMTU - 3; /* 3 bytes for UI LLC frame */ 180*45432Sbostic#else 181*45432Sbostic ifp->if_mtu = ETHERMTU; 182*45432Sbostic#endif IEEELCC 183*45432Sbostic 184*45432Sbostic /* 185*45432Sbostic * Read the ethernet address off the board. 186*45432Sbostic * Save it and also write it to the edlc chip. 187*45432Sbostic */ 188*45432Sbostic for (i = 0; i < ETH_ADDR_SIZE; i++){ 189*45432Sbostic us->us_addr[i] = MM_IN(&addr->un_eprom[UN_EADDROFF+i]); 190*45432Sbostic MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]); 191*45432Sbostic } 192*45432Sbostic printf("un%d: ethernet address ", ifp->if_unit); 193*45432Sbostic unprintethaddr(us->us_addr); 194*45432Sbostic printf("\n"); 195*45432Sbostic ifp->if_init = uninit; 196*45432Sbostic ifp->if_ioctl = unioctl; 197*45432Sbostic ifp->if_output = unoutput; 198*45432Sbostic ifp->if_reset = unreset; 199*45432Sbostic ifp->if_flags = IFF_BROADCAST; 200*45432Sbostic#ifdef ISO 201*45432Sbostic ifp->if_flags |= IFF_EAVESDROP; 202*45432Sbostic#endif ISO 203*45432Sbostic if_attach(ifp); 204*45432Sbostic DEBUGF(undebug, printf("un%d: attached\n", iod->iod_unit);) 205*45432Sbostic#ifdef ATR 206*45432Sbostic restore_window(old_window); 207*45432Sbostic#endif ATR 208*45432Sbostic} 209*45432Sbostic 210*45432Sbostic/* 211*45432Sbostic * unreset - reset interface 212*45432Sbostic */ 213*45432Sbosticunreset(unit) 214*45432Sbostic register unsigned int unit; 215*45432Sbostic{ 216*45432Sbostic register struct iocc_device *iod; 217*45432Sbostic 218*45432Sbostic if (unit < NUN && (iod = uninfo[unit]) != 0 && iod->iod_alive != 0){ 219*45432Sbostic un_softc[unit].us_if.if_flags &= ~IFF_RUNNING; 220*45432Sbostic DEBUGF(undebug, printf("un%d: reset\n", unit);) 221*45432Sbostic uninit(unit); 222*45432Sbostic } 223*45432Sbostic} 224*45432Sbostic 225*45432Sbostic/* 226*45432Sbostic * uninit - initialize interface, enable packet reception, start any 227*45432Sbostic * pending writes 228*45432Sbostic */ 229*45432Sbosticuninit(unit) 230*45432Sbostic register int unit; 231*45432Sbostic{ 232*45432Sbostic register struct un_softc *us = &un_softc[unit]; 233*45432Sbostic register struct ifnet *ifp = &us->us_if; 234*45432Sbostic register int s; 235*45432Sbostic register struct undevice *addr; 236*45432Sbostic register int i; 237*45432Sbostic 238*45432Sbostic if (ifp->if_addrlist == (struct ifaddr *) 0){ 239*45432Sbostic /* no address */ 240*45432Sbostic return; 241*45432Sbostic } 242*45432Sbostic if ((ifp->if_flags & IFF_RUNNING) == 0){ 243*45432Sbostic int old_window; 244*45432Sbostic 245*45432Sbostic addr = (struct undevice *) (uninfo[unit]->iod_addr); 246*45432Sbostic#ifdef ATR 247*45432Sbostic move_window(old_window, addr); 248*45432Sbostic#endif ATR 249*45432Sbostic s = splimp(); 250*45432Sbostic us->us_nextpage = unzap(addr); /* initialize hardware */ 251*45432Sbostic /* unzap returns next receive page to be used */ 252*45432Sbostic for (i = 0; i < ETH_ADDR_SIZE; i++){ 253*45432Sbostic MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]); 254*45432Sbostic } 255*45432Sbostic us->us_oactive = 0; /* output not active */ 256*45432Sbostic /* turn adapter on */ 257*45432Sbostic ifp->if_flags |= IFF_RUNNING; 258*45432Sbostic MM_OUT(&addr->un_csr, UN_PAVIENB); 259*45432Sbostic /* Allow packet available interrupts */ 260*45432Sbostic UN_GLOBIENB(us->us_nextpage); /* global interrrupt enable */ 261*45432Sbostic if (ifp->if_snd.ifq_head){ /* anything on send queue */ 262*45432Sbostic struct mbuf *m; 263*45432Sbostic 264*45432Sbostic IF_DEQUEUE(&ifp->if_snd, m); 265*45432Sbostic unput(us, addr, m, 0); 266*45432Sbostic unstart(us, addr, 0); 267*45432Sbostic if (ifp->if_snd.ifq_head){ 268*45432Sbostic IF_DEQUEUE(&ifp->if_snd, m); 269*45432Sbostic unput(us, addr, m, 1); 270*45432Sbostic } 271*45432Sbostic } 272*45432Sbostic splx(s); 273*45432Sbostic#ifdef ATR 274*45432Sbostic restore_window(old_window); 275*45432Sbostic#endif ATR 276*45432Sbostic } 277*45432Sbostic DEBUGF(undebug, printf("un%d: init'ed\n", unit);) 278*45432Sbostic} 279*45432Sbostic 280*45432Sbostic/* 281*45432Sbostic * unstart - start output from one of the adapter's 2 transmit buffers 282*45432Sbostic */ 283*45432Sbosticunstart(us, addr, xbuf) 284*45432Sbostic register struct un_softc *us; 285*45432Sbostic register struct undevice *addr; 286*45432Sbostic register int xbuf; 287*45432Sbostic{ 288*45432Sbostic us->us_oactive = 1; 289*45432Sbostic us->us_xbuf = xbuf; 290*45432Sbostic UN_XMIT(addr, us->us_xstart[xbuf]); 291*45432Sbostic MM_OUT(&addr->un_csr, UN_IENABLE); /* enable transmit done interrupt */ 292*45432Sbostic} 293*45432Sbostic 294*45432Sbostic/* 295*45432Sbostic * unint - interrupt handler. find the cause of the interrupt and 296*45432Sbostic * dispatch an appropriate handler routine. 297*45432Sbostic */ 298*45432Sbosticunint(unit) 299*45432Sbostic register int unit; 300*45432Sbostic{ 301*45432Sbostic register struct un_softc *us = &un_softc[unit]; 302*45432Sbostic register struct undevice *addr = 303*45432Sbostic (struct undevice *) uninfo[unit]->iod_addr; 304*45432Sbostic register char status; 305*45432Sbostic register int rc = 1; 306*45432Sbostic#ifdef ATR 307*45432Sbostic register int old_window; 308*45432Sbostic 309*45432Sbostic move_window(old_window, addr); 310*45432Sbostic#endif ATR 311*45432Sbostic 312*45432Sbostic UN_DISABLE(us->us_nextpage); 313*45432Sbostic while ((status = ~MM_IN(&addr->un_csr)) & UN_PAVINT){ 314*45432Sbostic DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b", 315*45432Sbostic unit, status & 0xff, UN_CSRBITS);) 316*45432Sbostic unrint(unit, us, addr); 317*45432Sbostic rc = 0; 318*45432Sbostic } 319*45432Sbostic if (status & UN_TXRINT){ 320*45432Sbostic DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b", 321*45432Sbostic unit, status & 0xff, UN_CSRBITS);) 322*45432Sbostic unxint(unit, us, addr); 323*45432Sbostic rc = 0; 324*45432Sbostic } 325*45432Sbostic UN_ENABLE(us->us_nextpage); 326*45432Sbostic#ifdef ATR 327*45432Sbostic restore_window(old_window); 328*45432Sbostic#endif ATR 329*45432Sbostic return(rc); 330*45432Sbostic} 331*45432Sbostic 332*45432Sbostic/* 333*45432Sbostic * unrint - interrupt handler for packet reception. 334*45432Sbostic * 335*45432Sbostic * log error if error bits are latched, examine packet to determine 336*45432Sbostic * type, if can't determine packet length from type, drop packet. 337*45432Sbostic * otherwise decapsulate packet based on type and pass to an appropriate 338*45432Sbostic * higher-level input routine. 339*45432Sbostic */ 340*45432Sbosticunrint(unit, us, addr) 341*45432Sbostic int unit; 342*45432Sbostic register struct un_softc *us; 343*45432Sbostic register struct undevice *addr; 344*45432Sbostic{ 345*45432Sbostic register struct ether_header *eh; 346*45432Sbostic register struct mbuf *m; 347*45432Sbostic register int len; 348*45432Sbostic register int off; 349*45432Sbostic int resid; 350*45432Sbostic struct ifqueue *inq; 351*45432Sbostic char status = MM_IN(&addr->un_edlc.rstat); 352*45432Sbostic u_short type; 353*45432Sbostic u_short ungetushortatoff(); 354*45432Sbostic#ifdef IEEELLC 355*45432Sbostic struct ether_header ehbuf; 356*45432Sbostic#endif IEEELLC 357*45432Sbostic 358*45432Sbostic MM_OUT(&addr->un_edlc.rstat, status); /* clear status */ 359*45432Sbostic /* (the hardware xor's in the value of status setting rstat to 0) */ 360*45432Sbostic DEBUGF(undebug & 0x2, printf(" rstat = %b", status, RS_BITS);) 361*45432Sbostic /* 362*45432Sbostic * Latch errors. (Errors found correspond to packets 363*45432Sbostic * that were received prior to the current packet 364*45432Sbostic * since packet available interrupts are generated 365*45432Sbostic * for good packets only.) 366*45432Sbostic */ 367*45432Sbostic if (status & RS_ERR){ 368*45432Sbostic DEBUGF(undebug, printf("unrint: input error\n");) 369*45432Sbostic us->us_if.if_ierrors++; 370*45432Sbostic } 371*45432Sbostic us->us_if.if_ipackets++; 372*45432Sbostic 373*45432Sbostic /* 374*45432Sbostic * determine the length of the received packet. 375*45432Sbostic */ 376*45432Sbostic len = 0; 377*45432Sbostic off = us->us_nextpage; 378*45432Sbostic 379*45432Sbostic#define BUMP(page) if (++(page) == UN_NUMRBUFS) page = 0 380*45432Sbostic while ((MM_IN(&addr->un_pram[us->us_nextpage]) & UN_LAST_PAGE) == 0){ 381*45432Sbostic len += UN_RBUFSIZE; 382*45432Sbostic BUMP(us->us_nextpage); 383*45432Sbostic } 384*45432Sbostic len += (MM_IN(&addr->un_pram[us->us_nextpage]) & 385*45432Sbostic UN_PAGE_LENGTH_MASK) + 1; 386*45432Sbostic BUMP(us->us_nextpage); 387*45432Sbostic#undef BUMP 388*45432Sbostic DEBUGF(undebug & 0x2, printf(" len = %d ", len);) 389*45432Sbostic if (len > UN_XBSIZE){ 390*45432Sbostic printf("un%d: huge packet!\n",unit); 391*45432Sbostic goto chuckit; 392*45432Sbostic } 393*45432Sbostic /* 394*45432Sbostic * Process the packet 395*45432Sbostic */ 396*45432Sbostic eh = (struct ether_header *) &addr->un_rcvbuf[off][0]; 397*45432Sbostic DEBUGF(undebug & 0x2, 398*45432Sbostic { char cbuf[6]; 399*45432Sbostic printf(" from = "); 400*45432Sbostic bcopyin(eh->ether_shost, cbuf, sizeof(cbuf)); 401*45432Sbostic unprintethaddr(cbuf); 402*45432Sbostic printf(" to = "); 403*45432Sbostic bcopyin(eh->ether_dhost, cbuf, sizeof(cbuf)); 404*45432Sbostic unprintethaddr(cbuf); 405*45432Sbostic printf(" "); } 406*45432Sbostic ) 407*45432Sbostic len -= sizeof(struct ether_header); 408*45432Sbostic type = ntohs((u_short) MM_INW(&eh->ether_type)); 409*45432Sbostic /* 410*45432Sbostic * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL 411*45432Sbostic * have (type - ETHERTYPE_TRAIL) * 512 bytes of data followed by 412*45432Sbostic * a type field and then a (variable length) header 413*45432Sbostic */ 414*45432Sbostic if (type >= ETHERTYPE_TRAIL && 415*45432Sbostic type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER){ 416*45432Sbostic off = (type - ETHERTYPE_TRAIL) * 512; 417*45432Sbostic if (off >= ETHERMTU){ 418*45432Sbostic goto chuckit; 419*45432Sbostic } 420*45432Sbostic type = ungetushortatoff(addr, eh, off); 421*45432Sbostic resid = ungetushortatoff(addr, eh, off + 2); 422*45432Sbostic if (off + resid > len){ 423*45432Sbostic goto chuckit; 424*45432Sbostic } 425*45432Sbostic len = off + resid; 426*45432Sbostic } else { 427*45432Sbostic off = 0; 428*45432Sbostic } 429*45432Sbostic if (len == 0){ 430*45432Sbostic goto chuckit; 431*45432Sbostic } 432*45432Sbostic 433*45432Sbostic#ifdef IEEELLC 434*45432Sbostic if (type <= ETHERMTU) { 435*45432Sbostic /* may need ether_header for XID, TEST LLC functions */ 436*45432Sbostic ehbuf = *eh; 437*45432Sbostic } 438*45432Sbostic#endif IEEELLC 439*45432Sbostic 440*45432Sbostic /* 441*45432Sbostic * pull packet off interface. if off is non-zero, the 442*45432Sbostic * packet has a trailing "header". unget will move this 443*45432Sbostic * header to the front, but we still have to remove the 444*45432Sbostic * type and length fields from the front of the data. 445*45432Sbostic */ 446*45432Sbostic m = unget(addr, (char *) eh, len, off, &us->us_if); 447*45432Sbostic /* 448*45432Sbostic * update the full page pointer and clear the packet available 449*45432Sbostic * flag if necessary. update the fpp here to free the on-board 450*45432Sbostic * receive pages as soon as possible. 451*45432Sbostic */ 452*45432Sbostic unupdatefpp(addr, us->us_nextpage); 453*45432Sbostic if (m != 0){ 454*45432Sbostic if (off){ 455*45432Sbostic#ifdef ISO 456*45432Sbostic /* 457*45432Sbostic * Move snpa header over by 4 bytes to skip 458*45432Sbostic * the trailer Type and Header length fields. 459*45432Sbostic */ 460*45432Sbostic struct snpa_hdr sh; 461*45432Sbostic 462*45432Sbostic bcopy(mtod(m, char *), (caddr_t)&sh, sizeof(struct snpa_hdr)); 463*45432Sbostic m->m_off += 2 * sizeof(u_short); 464*45432Sbostic m->m_len -= 2 * sizeof(u_short); 465*45432Sbostic bcopy((caddr_t)&sh, mtod(m, char *), sizeof(struct snpa_hdr)); 466*45432Sbostic#else ISO 467*45432Sbostic struct ifnet *ifp; 468*45432Sbostic /* 469*45432Sbostic * bcopy is used since word moves must be on 4 byte 470*45432Sbostic * boundaries on the RT PC 471*45432Sbostic */ 472*45432Sbostic bcopy(mtod(m, char *), (char *) &ifp, sizeof(ifp)); 473*45432Sbostic m->m_off += 2 * sizeof(u_short); 474*45432Sbostic m->m_len -= 2 * sizeof(u_short); 475*45432Sbostic bcopy((char *) &ifp, mtod(m, char *), sizeof(ifp)); 476*45432Sbostic#endif ISO 477*45432Sbostic } 478*45432Sbostic switch (type){ 479*45432Sbostic#ifdef INET 480*45432Sbostic case ETHERTYPE_IP: 481*45432Sbostic { 482*45432Sbostic int s; 483*45432Sbostic 484*45432Sbostic DEBUGF(undebug & 0x2, printf("ip packet\n");) 485*45432Sbostic schednetisr(NETISR_IP); 486*45432Sbostic s = splimp(); 487*45432Sbostic inq = &ipintrq; 488*45432Sbostic if (IF_QFULL(inq)){ 489*45432Sbostic DEBUGF(undebug & 0x2, printf(" qfull\n");) 490*45432Sbostic IF_DROP(inq); 491*45432Sbostic m_freem(m); 492*45432Sbostic } else { 493*45432Sbostic IF_ENQUEUE(inq, m); 494*45432Sbostic DEBUGF(undebug & 0x2, printf(" queued\n");) 495*45432Sbostic } 496*45432Sbostic splx(s); 497*45432Sbostic break; 498*45432Sbostic } 499*45432Sbostic 500*45432Sbostic case ETHERTYPE_ARP: 501*45432Sbostic DEBUGF(undebug & 0x2, printf("arp packet\n");) 502*45432Sbostic arpinput(&us->us_ac, m); /* arpinput frees m */ 503*45432Sbostic break; 504*45432Sbostic#endif INET 505*45432Sbostic#ifdef NS 506*45432Sbostic case ETHERTYPE_NS: 507*45432Sbostic DEBUGF(undebug & 0x2, printf("ns packet\n");) 508*45432Sbostic schednetisr(NETISR_NS); 509*45432Sbostic inq = &nsintrq; 510*45432Sbostic break; 511*45432Sbostic#endif NS 512*45432Sbostic#ifndef IEEELLC 513*45432Sbostic#ifdef ISO 514*45432Sbostic case ETHERTYPE_CLNP: /* should be CLNL */ 515*45432Sbostic DEBUGF(undebug & 0x2, printf("clnl packet\n");) 516*45432Sbostic 517*45432Sbostic /* IFF_EAVESDROP can not be turned off for Ethernet */ 518*45432Sbostic 519*45432Sbostic schednetisr(NETISR_CLNP); 520*45432Sbostic inq = &clnlintrq; 521*45432Sbostic if (IF_QFULL(inq)){ 522*45432Sbostic DEBUGF(undebug & 0x2, printf(" qfull\n");) 523*45432Sbostic IF_DROP(inq); 524*45432Sbostic m_freem(m); 525*45432Sbostic } else { 526*45432Sbostic IF_ENQUEUE(inq, m); 527*45432Sbostic DEBUGF(undebug & 0x2, printf(" queued\n");) 528*45432Sbostic } 529*45432Sbostic break; 530*45432Sbostic#endif ISO 531*45432Sbostic default: 532*45432Sbostic DEBUGF(undebug & 0x2, printf("unknown packet\n");) 533*45432Sbostic m_freem(m); 534*45432Sbostic break; 535*45432Sbostic#else 536*45432Sbostic default: { 537*45432Sbostic struct llc *l; 538*45432Sbostic caddr_t pkt_start; 539*45432Sbostic#ifdef ISO 540*45432Sbostic#define PREPENDED_SIZE sizeof(struct snpa_hdr) 541*45432Sbostic#else 542*45432Sbostic#define PREPENDED_SIZE sizeof(struct ifnet *) 543*45432Sbostic#endif ISO 544*45432Sbostic if (type > ETHERMTU) 545*45432Sbostic goto not802; 546*45432Sbostic 547*45432Sbostic /* 548*45432Sbostic * This assumes that the snpa header is in the same mbuf 549*45432Sbostic * as the llc header. Currently this is ok, but if 550*45432Sbostic * unget allocates a cluster, this will not be the case 551*45432Sbostic */ 552*45432Sbostic pkt_start = mtod(m, caddr_t); 553*45432Sbostic l = (struct llc *) (pkt_start + PREPENDED_SIZE); 554*45432Sbostic 555*45432Sbostic IFDEBUG(D_ETHER) 556*45432Sbostic printf("unrint: llc: length %d, control x%x:\n", type, 557*45432Sbostic l->llc_control); 558*45432Sbostic ENDDEBUG 559*45432Sbostic 560*45432Sbostic switch (l->llc_control) { 561*45432Sbostic case LLC_UI: 562*45432Sbostic /* LLC_UI_P forbidden in class 1 service */ 563*45432Sbostic#ifdef ISO 564*45432Sbostic if (l->llc_dsap == LLC_ISO_LSAP) { 565*45432Sbostic if ((IS_MULTICAST(ehbuf.ether_dhost)) && 566*45432Sbostic ((us->us_if.if_flags & IFF_EAVESDROP) == 0) && 567*45432Sbostic (!snpac_ownmulti(ehbuf.ether_dhost, 6))) { 568*45432Sbostic m_freem(m); 569*45432Sbostic return; 570*45432Sbostic } 571*45432Sbostic 572*45432Sbostic /* move struct snpa_header over the llc header */ 573*45432Sbostic clnp_ypocb(pkt_start, pkt_start + 3, 574*45432Sbostic PREPENDED_SIZE); 575*45432Sbostic m->m_off += 3; 576*45432Sbostic m->m_len -= 3; 577*45432Sbostic 578*45432Sbostic DEBUGF(undebug & 0x2, printf("clnp packet\n");) 579*45432Sbostic schednetisr(NETISR_CLNP); 580*45432Sbostic inq = &clnlintrq; 581*45432Sbostic if (IF_QFULL(inq)){ 582*45432Sbostic DEBUGF(undebug & 0x2, printf(" qfull\n");) 583*45432Sbostic IF_DROP(inq); 584*45432Sbostic m_freem(m); 585*45432Sbostic } else { 586*45432Sbostic IF_ENQUEUE(inq, m); 587*45432Sbostic DEBUGF(undebug & 0x2, printf(" queued\n");) 588*45432Sbostic } 589*45432Sbostic return; 590*45432Sbostic } else { 591*45432Sbostic IFDEBUG(D_ETHER) 592*45432Sbostic printf("unrint: unknown llc sap\n"); 593*45432Sbostic ENDDEBUG 594*45432Sbostic m_freem(m); 595*45432Sbostic return; 596*45432Sbostic } 597*45432Sbostic#endif ISO 598*45432Sbostic break; 599*45432Sbostic/* LLC_XID, LLC_XID_P, LLC_TEST, and LLC_TEST_P are untested */ 600*45432Sbostic case LLC_XID: 601*45432Sbostic case LLC_XID_P: /* control field is untouched for resp */ 602*45432Sbostic if(m->m_len < 6) 603*45432Sbostic goto not802; 604*45432Sbostic l->llc_fid = LLC_IEEE_basic_format; 605*45432Sbostic l->llc_class = LLC_CLASS1; 606*45432Sbostic l->llc_window = 0; 607*45432Sbostic l->llc_dsap = l->llc_ssap = 0; 608*45432Sbostic /* FALL THROUGH */ 609*45432Sbostic case LLC_TEST: 610*45432Sbostic case LLC_TEST_P: { 611*45432Sbostic struct ifnet *ifp = &us->us_if; 612*45432Sbostic struct sockaddr_iso siso; 613*45432Sbostic u_char c = l->llc_dsap; 614*45432Sbostic l->llc_dsap = l->llc_ssap; 615*45432Sbostic l->llc_ssap = c; 616*45432Sbostic 617*45432Sbostic /* Do not TEST or XID to multicasts */ 618*45432Sbostic if (IS_MULTICAST(ehbuf.ether_dhost)) { 619*45432Sbostic m_freem(m); 620*45432Sbostic break; 621*45432Sbostic } 622*45432Sbostic 623*45432Sbostic siso.siso_family = AF_ISO; 624*45432Sbostic bcopy(ehbuf.ether_shost, siso.siso_addr.sna_idi, 6); 625*45432Sbostic siso.siso_addr.isoa_afi = AFI_SNA; 626*45432Sbostic siso.siso_addr.isoa_len = 7; 627*45432Sbostic 628*45432Sbostic /* trim off prepended snpa_hdr or ifp */ 629*45432Sbostic m->m_off += PREPENDED_SIZE; 630*45432Sbostic m->m_len -= PREPENDED_SIZE; 631*45432Sbostic 632*45432Sbostic unoutput(ifp, m, &siso); 633*45432Sbostic return; 634*45432Sbostic } 635*45432Sbostic not802: 636*45432Sbostic default: 637*45432Sbostic DEBUGF(undebug & 0x2, printf("unknown packet\n");) 638*45432Sbostic m_freem(m); 639*45432Sbostic break; 640*45432Sbostic } 641*45432Sbostic } 642*45432Sbostic#endif IEEELLC 643*45432Sbostic } 644*45432Sbostic } 645*45432Sbostic return; 646*45432Sbosticchuckit: 647*45432Sbostic DEBUGF(undebug, printf("unrint: packet dropped\n");) 648*45432Sbostic unupdatefpp(addr, us->us_nextpage); 649*45432Sbostic} 650*45432Sbostic 651*45432Sbostic/* 652*45432Sbostic * unxint - interrupt handler for transmit ready 653*45432Sbostic */ 654*45432Sbosticunxint(unit, us, addr) 655*45432Sbostic register int unit; 656*45432Sbostic register struct un_softc *us; 657*45432Sbostic register struct undevice *addr; 658*45432Sbostic{ 659*45432Sbostic register char status; 660*45432Sbostic register int next_buf; 661*45432Sbostic 662*45432Sbostic /* 663*45432Sbostic * collect stats on last packet 664*45432Sbostic */ 665*45432Sbostic status = MM_IN(&addr->un_edlc.xstat); 666*45432Sbostic MM_OUT(&addr->un_edlc.xstat, status); /* clear status bits */ 667*45432Sbostic DEBUGF(undebug & 0x2, printf(" unxint: xstat = %b\n", 668*45432Sbostic status & 0xff, XS_BITS);) 669*45432Sbostic if (status & XS_16CL){ 670*45432Sbostic us->us_if.if_collisions += 16; 671*45432Sbostic us->us_if.if_oerrors++; 672*45432Sbostic printf("un%d: ethernet jammed\n", unit); 673*45432Sbostic } 674*45432Sbostic else if (status & XS_SHRT){ 675*45432Sbostic us->us_if.if_oerrors++; 676*45432Sbostic printf( "un%d: ethernet not responding (is it connected?)\n", 677*45432Sbostic unit); 678*45432Sbostic } 679*45432Sbostic else { 680*45432Sbostic us->us_if.if_opackets++; 681*45432Sbostic us->us_if.if_collisions += UN_NCOLL(addr); 682*45432Sbostic } 683*45432Sbostic DEBUGF(undebug & 0x2, 684*45432Sbostic printf(" ipkt = %d ierr = %d okt = %d oerr = %d coll = %d\n", 685*45432Sbostic us->us_if.if_ipackets, us->us_if.if_ierrors, 686*45432Sbostic us->us_if.if_opackets, us->us_if.if_oerrors, 687*45432Sbostic us->us_if.if_collisions);) 688*45432Sbostic /* mark the current transmit buffer empty */ 689*45432Sbostic us->us_xfull[us->us_xbuf] = 0; 690*45432Sbostic /* switch to the other transmit buffer */ 691*45432Sbostic next_buf = 1 - us->us_xbuf; 692*45432Sbostic if (us->us_xfull[next_buf]){ /* if it's full */ 693*45432Sbostic unstart(us, addr, next_buf); /* start output from it */ 694*45432Sbostic if (us->us_if.if_snd.ifq_head){ /* if more on out queue */ 695*45432Sbostic struct mbuf *m; 696*45432Sbostic 697*45432Sbostic IF_DEQUEUE(&us->us_if.if_snd, m); /* fill empty buf */ 698*45432Sbostic unput(us, addr, m, 1 - next_buf); 699*45432Sbostic } 700*45432Sbostic } 701*45432Sbostic else { /* the other transmit buffer is empty */ 702*45432Sbostic us->us_oactive = 0; 703*45432Sbostic MM_OUT(&addr->un_csr, UN_PAVIENB); /* Turn off TxRIENB */ 704*45432Sbostic } 705*45432Sbostic} 706*45432Sbostic 707*45432Sbostic/* 708*45432Sbostic * unoutput - ethernet output routine. encapsulate a packet of type 709*45432Sbostic * family for the local net. use trailer local net encapsulation if 710*45432Sbostic * the number of bytes in the mbufs after the first is a multiple of 711*45432Sbostic * 512. 712*45432Sbostic */ 713*45432Sbosticunoutput(ifp, m0, dst) 714*45432Sbostic register struct ifnet *ifp; 715*45432Sbostic register struct mbuf *m0; 716*45432Sbostic register struct sockaddr *dst; 717*45432Sbostic{ 718*45432Sbostic u_short type; 719*45432Sbostic int s; 720*45432Sbostic int error; 721*45432Sbostic char edst[ETH_ADDR_SIZE]; 722*45432Sbostic struct in_addr idst; 723*45432Sbostic register struct un_softc *us = &un_softc[ifp->if_unit]; 724*45432Sbostic register struct mbuf *m = m0; 725*45432Sbostic register struct ether_header *eh; 726*45432Sbostic int off; 727*45432Sbostic struct mbuf *m_get(); 728*45432Sbostic int usetrailers; 729*45432Sbostic 730*45432Sbostic if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)){ 731*45432Sbostic error = ENETDOWN; 732*45432Sbostic goto bad; 733*45432Sbostic } 734*45432Sbostic switch (dst->sa_family){ 735*45432Sbostic 736*45432Sbostic#ifdef INET 737*45432Sbostic case AF_INET: 738*45432Sbostic idst = ((struct sockaddr_in *)dst)->sin_addr; 739*45432Sbostic if (!arpresolve(&us->us_ac, m, &idst, edst, &usetrailers)){ 740*45432Sbostic /* not resolved */ 741*45432Sbostic return(0); 742*45432Sbostic } 743*45432Sbostic off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 744*45432Sbostic if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 745*45432Sbostic m->m_off >= MMINOFF + 2 * sizeof(u_short)){ 746*45432Sbostic type = ETHERTYPE_TRAIL + (off>>9); 747*45432Sbostic m->m_off -= 2 * sizeof(u_short); 748*45432Sbostic m->m_len += 2 * sizeof(u_short); 749*45432Sbostic *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 750*45432Sbostic *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 751*45432Sbostic /* 752*45432Sbostic * Packet to be sent with trailer, move first packet 753*45432Sbostic * (control information) to end of chain. 754*45432Sbostic */ 755*45432Sbostic while (m->m_next) 756*45432Sbostic m = m->m_next; 757*45432Sbostic m->m_next = m0; 758*45432Sbostic m = m0->m_next; 759*45432Sbostic m0->m_next = 0; 760*45432Sbostic m0 = m; 761*45432Sbostic } 762*45432Sbostic else { 763*45432Sbostic type = ETHERTYPE_IP; 764*45432Sbostic } 765*45432Sbostic break; 766*45432Sbostic#endif INET 767*45432Sbostic#ifdef NS 768*45432Sbostic case AF_NS: 769*45432Sbostic bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 770*45432Sbostic (caddr_t)edst, sizeof(edst)); 771*45432Sbostic type = ETHERTYPE_NS; 772*45432Sbostic off = 0; 773*45432Sbostic break; 774*45432Sbostic#endif NS 775*45432Sbostic#ifdef ISO 776*45432Sbostic case AF_ISO: { 777*45432Sbostic int ret; 778*45432Sbostic int len; 779*45432Sbostic struct iso_addr *dst_nsap = &((struct sockaddr_iso *)dst)->siso_addr; 780*45432Sbostic 781*45432Sbostic if ((ret = iso_tryloopback(m, dst)) >= 0) 782*45432Sbostic return (ret); 783*45432Sbostic else if (ret = iso_snparesolve(&us->us_ac.ac_if, dst_nsap, edst, &len)){ 784*45432Sbostic /* not resolved */ 785*45432Sbostic IFDEBUG(D_ETHER) 786*45432Sbostic printf("unoutput: clnp packet dropped\n"); 787*45432Sbostic ENDDEBUG 788*45432Sbostic m_freem(m); 789*45432Sbostic return(ret); 790*45432Sbostic } else if (len != 6) { 791*45432Sbostic printf("unoutput: snpa len is not 6 (%d)\n", len); 792*45432Sbostic m_freem(m); 793*45432Sbostic return(ENETUNREACH); 794*45432Sbostic } 795*45432Sbostic 796*45432Sbostic#ifndef IEEELLC 797*45432Sbostic type = ETHERTYPE_CLNP; 798*45432Sbostic#else 799*45432Sbostic /* check for enough space for LLC header */ 800*45432Sbostic { 801*45432Sbostic struct mbuf *llcm; 802*45432Sbostic char *cp; 803*45432Sbostic if (m->m_off >= MMAXOFF || m->m_off < MMINOFF + 3) { 804*45432Sbostic MGET(llcm, M_DONTWAIT, MT_DATA); 805*45432Sbostic if (llcm == NULL) { 806*45432Sbostic m_freem(m); 807*45432Sbostic return(0); 808*45432Sbostic } 809*45432Sbostic llcm->m_off = MMAXOFF - 3; 810*45432Sbostic llcm->m_len = 3; 811*45432Sbostic llcm->m_next = m; 812*45432Sbostic m = llcm; 813*45432Sbostic } else { 814*45432Sbostic m->m_off -= 3; 815*45432Sbostic m->m_len += 3; 816*45432Sbostic } 817*45432Sbostic type = m_datalen(m); 818*45432Sbostic 819*45432Sbostic cp = mtod(m, u_char *); 820*45432Sbostic cp[0] = cp[1] = LLC_ISO_LSAP; cp[2] = LLC_UI; 821*45432Sbostic off = 0; 822*45432Sbostic } 823*45432Sbostic#endif IEEELLC 824*45432Sbostic off = 0; 825*45432Sbostic IFDEBUG(D_ETHER) 826*45432Sbostic int i; 827*45432Sbostic printf("unoutput: sending pkt to: "); 828*45432Sbostic for (i=0; i<6; i++) 829*45432Sbostic printf("%x ", edst[i] & 0xff); 830*45432Sbostic#ifdef IEEELLC 831*45432Sbostic printf(" llc len %d", type); 832*45432Sbostic#endif IEEELLC 833*45432Sbostic printf("\n"); 834*45432Sbostic ENDDEBUG 835*45432Sbostic } break; 836*45432Sbostic#endif ISO 837*45432Sbostic case AF_UNSPEC: 838*45432Sbostic eh = (struct ether_header *)dst->sa_data; 839*45432Sbostic bcopy((char *)eh->ether_dhost, (caddr_t)edst, sizeof(edst)); 840*45432Sbostic type = eh->ether_type; 841*45432Sbostic break; 842*45432Sbostic default: 843*45432Sbostic printf("un%d: can't handle af%d\n", ifp->if_unit, 844*45432Sbostic dst->sa_family); 845*45432Sbostic error = EAFNOSUPPORT; 846*45432Sbostic goto bad; 847*45432Sbostic } 848*45432Sbostic /* 849*45432Sbostic * Add local net header. If no space in first mbuf, 850*45432Sbostic * allocate another. 851*45432Sbostic */ 852*45432Sbostic if (m->m_off > MMAXOFF || 853*45432Sbostic MMINOFF + sizeof(struct ether_header) > m->m_off){ 854*45432Sbostic m = m_get(M_DONTWAIT, MT_HEADER); 855*45432Sbostic /* 856*45432Sbostic * Note: m_get, m_freem etc. guard against concurrent 857*45432Sbostic * updates to the list of free mbufs. 858*45432Sbostic */ 859*45432Sbostic if (m == 0){ 860*45432Sbostic error = ENOBUFS; 861*45432Sbostic goto bad; 862*45432Sbostic } 863*45432Sbostic m->m_next = m0; 864*45432Sbostic m->m_off = MMINOFF; 865*45432Sbostic m->m_len = sizeof(struct ether_header); 866*45432Sbostic } else { 867*45432Sbostic m->m_off -= sizeof(struct ether_header); 868*45432Sbostic m->m_len += sizeof(struct ether_header); 869*45432Sbostic } 870*45432Sbostic eh = mtod(m, struct ether_header *); 871*45432Sbostic bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof(edst)); 872*45432Sbostic bcopy((caddr_t)us->us_addr, (caddr_t)eh->ether_shost, 873*45432Sbostic sizeof(eh->ether_shost)); 874*45432Sbostic bcopy((caddr_t)&type, (caddr_t)&eh->ether_type, sizeof(u_short)); 875*45432Sbostic 876*45432Sbostic /* 877*45432Sbostic * queue packet for transmission. if there is an empty 878*45432Sbostic * transmit buffer on the adapter, use it. 879*45432Sbostic */ 880*45432Sbostic s = splimp(); 881*45432Sbostic if (IF_QFULL(&ifp->if_snd)){ 882*45432Sbostic IF_DROP(&ifp->if_snd); 883*45432Sbostic error = ENOBUFS; 884*45432Sbostic goto qfull; 885*45432Sbostic } 886*45432Sbostic if (us->us_xfull[0] == 0 || us->us_xfull[1] == 0){ /* empty xmt buf */ 887*45432Sbostic struct undevice *addr = (struct undevice *) 888*45432Sbostic uninfo[ifp->if_unit]->iod_addr; 889*45432Sbostic int next_buf; 890*45432Sbostic#ifdef ATR 891*45432Sbostic int old_window; 892*45432Sbostic move_window(old_window, addr); 893*45432Sbostic#endif ATR 894*45432Sbostic if (us->us_xfull[0] == 0){ 895*45432Sbostic next_buf = 0; 896*45432Sbostic } 897*45432Sbostic else { 898*45432Sbostic next_buf = 1; 899*45432Sbostic } 900*45432Sbostic unput(us, addr, m, next_buf); 901*45432Sbostic if (us->us_oactive == 0){ 902*45432Sbostic unstart(us, addr, next_buf); 903*45432Sbostic } 904*45432Sbostic#ifdef ATR 905*45432Sbostic restore_window(old_window); 906*45432Sbostic#endif ATR 907*45432Sbostic } 908*45432Sbostic else { 909*45432Sbostic IF_ENQUEUE(&ifp->if_snd, m); 910*45432Sbostic } 911*45432Sbostic splx(s); 912*45432Sbostic return(0); 913*45432Sbosticqfull: 914*45432Sbostic m0 = m; 915*45432Sbostic splx(s); 916*45432Sbosticbad: 917*45432Sbostic m_freem(m0); 918*45432Sbostic return(error); 919*45432Sbostic} 920*45432Sbostic 921*45432Sbostic/* 922*45432Sbostic * unput - copy packet from an mbuf chain to one of the adapter's 923*45432Sbostic * transmit buffers. the packet is extended to the minimum legal 924*45432Sbostic * size if necessary. the extra bytes could be zeroed out to improve 925*45432Sbostic * security but are not to maximize performance. 926*45432Sbostic */ 927*45432Sbosticunput(us, addr, m, xbuf) 928*45432Sbostic struct un_softc *us; 929*45432Sbostic struct undevice *addr; 930*45432Sbostic register struct mbuf *m; 931*45432Sbostic register int xbuf; 932*45432Sbostic{ 933*45432Sbostic register unsigned off; 934*45432Sbostic register struct mbuf *mp; 935*45432Sbostic register char *bp; 936*45432Sbostic 937*45432Sbostic /* 938*45432Sbostic * compute starting address in transmit buffer. packets must be 939*45432Sbostic * "end_aligned". 940*45432Sbostic */ 941*45432Sbostic for (off = UN_XBSIZE, mp = m; mp; mp = mp->m_next){ 942*45432Sbostic off -= mp->m_len; 943*45432Sbostic } 944*45432Sbostic if (UN_XBSIZE - off < ETHERMIN + sizeof(struct ether_header)){ 945*45432Sbostic /* packet too short => extend it */ 946*45432Sbostic off = UN_XBSIZE - ETHERMIN - sizeof(struct ether_header); 947*45432Sbostic } 948*45432Sbostic if (xbuf == 1){ /* use the second buffer */ 949*45432Sbostic off += UN_XBSIZE; /* the 2 buffers are adjacent */ 950*45432Sbostic } 951*45432Sbostic bp = ((char *)(addr->un_xmtbuf)) + off; 952*45432Sbostic for (mp = m; mp; mp = mp->m_next){ 953*45432Sbostic register unsigned len = mp->m_len; 954*45432Sbostic 955*45432Sbostic bcopyout(mtod(mp, char *), bp, len); 956*45432Sbostic bp += len; 957*45432Sbostic } 958*45432Sbostic /* save starting address so interrupt handler can find it */ 959*45432Sbostic us->us_xstart[xbuf] = off; /* start address to be passed to adapter */ 960*45432Sbostic us->us_xfull[xbuf] = 1; /* mark buffer full */ 961*45432Sbostic m_freem(m); 962*45432Sbostic} 963*45432Sbostic 964*45432Sbostic/* 965*45432Sbostic * unget - copy packet from adapter's receive buffers into a chain of mbufs 966*45432Sbostic * 967*45432Sbostic */ 968*45432Sbosticstruct mbuf * 969*45432Sbosticunget(addr, unbuf, totlen, off0, ifp) 970*45432Sbostic struct undevice *addr; 971*45432Sbostic char *unbuf; 972*45432Sbostic register int totlen; 973*45432Sbostic int off0; 974*45432Sbostic struct ifnet *ifp; 975*45432Sbostic{ 976*45432Sbostic register struct mbuf *m; 977*45432Sbostic struct mbuf *top = 0; 978*45432Sbostic register struct mbuf **mp = ⊤ 979*45432Sbostic register int off = off0; 980*45432Sbostic register int len; 981*45432Sbostic register char *cp; 982*45432Sbostic#ifdef ISO 983*45432Sbostic int copied_snpa = 0; 984*45432Sbostic#endif ISO 985*45432Sbostic 986*45432Sbostic cp = unbuf + sizeof(struct ether_header); 987*45432Sbostic while (totlen > 0){ 988*45432Sbostic char *mcp; 989*45432Sbostic 990*45432Sbostic MGET(m, M_DONTWAIT, MT_DATA); 991*45432Sbostic if (m == 0) 992*45432Sbostic goto bad; 993*45432Sbostic if (off){ /* trailer exists */ 994*45432Sbostic len = totlen - off; 995*45432Sbostic cp = unbuf + sizeof(struct ether_header) + off; 996*45432Sbostic } else 997*45432Sbostic len = totlen; 998*45432Sbostic#ifdef ISO 999*45432Sbostic if (!copied_snpa) 1000*45432Sbostic len += sizeof(struct snpa_hdr); 1001*45432Sbostic#else ISO 1002*45432Sbostic if (ifp) 1003*45432Sbostic len += sizeof(ifp); 1004*45432Sbostic#endif ISO 1005*45432Sbostic if (len >= NBPG){ 1006*45432Sbostic MCLGET(m); 1007*45432Sbostic if (m->m_len == CLBYTES) 1008*45432Sbostic m->m_len = len = MIN(len, CLBYTES); 1009*45432Sbostic else 1010*45432Sbostic m->m_len = len = MIN(MLEN, len); 1011*45432Sbostic } else { 1012*45432Sbostic m->m_len = len = MIN(MLEN, len); 1013*45432Sbostic m->m_off = MMINOFF; 1014*45432Sbostic } 1015*45432Sbostic mcp = mtod(m, char *); 1016*45432Sbostic#ifdef ISO 1017*45432Sbostic if (!copied_snpa) { 1018*45432Sbostic /* 1019*45432Sbostic * Prepend snpa_hdr to first mbuf 1020*45432Sbostic * The hardcoded 12 below refers to the length of the dhost 1021*45432Sbostic * and shost fields. We recklessly assume 1022*45432Sbostic * the order of dhost,shost in the snpa_hdr is the same 1023*45432Sbostic * as the order in the ether_header. 1024*45432Sbostic */ 1025*45432Sbostic struct snpa_hdr *sh = (struct snpa_hdr *)mcp; 1026*45432Sbostic struct ether_header *eh = (struct ether_header *)unbuf; 1027*45432Sbostic 1028*45432Sbostic bcopy((char *) &ifp, (caddr_t)&sh->snh_ifp, sizeof(ifp)); 1029*45432Sbostic bcopy((caddr_t)eh, (caddr_t)sh->snh_dhost, 12); 1030*45432Sbostic mcp += sizeof(struct snpa_hdr); 1031*45432Sbostic len -= sizeof(struct snpa_hdr); 1032*45432Sbostic copied_snpa = 1; 1033*45432Sbostic } 1034*45432Sbostic#else ISO 1035*45432Sbostic if (ifp){ 1036*45432Sbostic /* prepend ifp to first mbuf */ 1037*45432Sbostic /* 1038*45432Sbostic * bcopy is used since since word moves must 1039*45432Sbostic * be on 4 byte boundaries on the RT PC 1040*45432Sbostic */ 1041*45432Sbostic bcopy((char *) &ifp, mcp, sizeof(ifp)); 1042*45432Sbostic mcp += sizeof(ifp); 1043*45432Sbostic len -= sizeof(ifp); 1044*45432Sbostic ifp = (struct ifnet *) 0; 1045*45432Sbostic } 1046*45432Sbostic#endif ISO 1047*45432Sbostic unbcopy(addr, cp, mcp, len); 1048*45432Sbostic cp += len; 1049*45432Sbostic *mp = m; 1050*45432Sbostic mp = &m->m_next; 1051*45432Sbostic if (off == 0){ 1052*45432Sbostic totlen -= len; 1053*45432Sbostic continue; 1054*45432Sbostic } 1055*45432Sbostic off += len; 1056*45432Sbostic if (off == totlen){ 1057*45432Sbostic cp = unbuf + sizeof(struct ether_header); 1058*45432Sbostic off = 0; 1059*45432Sbostic totlen = off0; 1060*45432Sbostic } 1061*45432Sbostic } 1062*45432Sbostic return(top); 1063*45432Sbosticbad: 1064*45432Sbostic m_freem(top); 1065*45432Sbostic return(0); 1066*45432Sbostic} 1067*45432Sbostic 1068*45432Sbostic 1069*45432Sbostic/* 1070*45432Sbostic * ioctl - process an ioctl request. 1071*45432Sbostic */ 1072*45432Sbosticunioctl(ifp, cmd, data) 1073*45432Sbostic register struct ifnet *ifp; 1074*45432Sbostic register int cmd; 1075*45432Sbostic register caddr_t data; 1076*45432Sbostic{ 1077*45432Sbostic register struct ifaddr *ifa = (struct ifaddr *)data; 1078*45432Sbostic register int s = splimp(); 1079*45432Sbostic register int error = 0; 1080*45432Sbostic 1081*45432Sbostic switch (cmd){ 1082*45432Sbostic case SIOCSIFADDR: 1083*45432Sbostic ifp->if_flags |= IFF_UP; 1084*45432Sbostic 1085*45432Sbostic switch (ifa->ifa_addr.sa_family){ 1086*45432Sbostic#ifdef INET 1087*45432Sbostic case AF_INET: 1088*45432Sbostic uninit(ifp->if_unit); /* before arpwhohas */ 1089*45432Sbostic ((struct arpcom *) ifp)->ac_ipaddr = 1090*45432Sbostic IA_SIN(ifa)->sin_addr; 1091*45432Sbostic arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 1092*45432Sbostic break; 1093*45432Sbostic#endif INET 1094*45432Sbostic#ifdef NS 1095*45432Sbostic case AF_NS: 1096*45432Sbostic { 1097*45432Sbostic struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 1098*45432Sbostic struct un_softc *us = &un_softc[ifp->if_unit]; 1099*45432Sbostic 1100*45432Sbostic if (ns_nullhost(*ina)) 1101*45432Sbostic ina->x_host = *(union ns_host *)(us->us_addr); 1102*45432Sbostic else { 1103*45432Sbostic ifp->if_flags &= ~IFF_RUNNING; 1104*45432Sbostic bcopy((caddr_t) ina->x_host.c_host, 1105*45432Sbostic (caddr_t) us->us_addr, sizeof(us->us_addr)); 1106*45432Sbostic /* 1107*45432Sbostic * the uninit will set the hardware address 1108*45432Sbostic * since the IFF_RUNNING flag is off 1109*45432Sbostic */ 1110*45432Sbostic } 1111*45432Sbostic uninit(ifp->if_unit); 1112*45432Sbostic break; 1113*45432Sbostic } 1114*45432Sbostic#endif NS 1115*45432Sbostic default: 1116*45432Sbostic uninit(ifp->if_unit); 1117*45432Sbostic break; 1118*45432Sbostic } 1119*45432Sbostic break; 1120*45432Sbostic case SIOCSIFFLAGS: 1121*45432Sbostic if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & 1122*45432Sbostic IFF_RUNNING){ 1123*45432Sbostic#ifdef ATR 1124*45432Sbostic int old_window; 1125*45432Sbostic#endif ATR 1126*45432Sbostic struct undevice *addr; 1127*45432Sbostic 1128*45432Sbostic addr = (struct undevice *) uninfo[ifp->if_unit]-> 1129*45432Sbostic iod_addr; 1130*45432Sbostic#ifdef ATR 1131*45432Sbostic move_window(old_window, addr); 1132*45432Sbostic#endif ATR 1133*45432Sbostic (void) unzap((struct undevice *) addr); 1134*45432Sbostic ifp->if_flags &= ~IFF_RUNNING; 1135*45432Sbostic#ifdef ATR 1136*45432Sbostic restore_window(old_window); 1137*45432Sbostic#endif ATR 1138*45432Sbostic } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & 1139*45432Sbostic IFF_RUNNING) == 0) 1140*45432Sbostic uninit(ifp->if_unit); 1141*45432Sbostic break; 1142*45432Sbostic default: 1143*45432Sbostic error = EINVAL; 1144*45432Sbostic } 1145*45432Sbostic splx(s); 1146*45432Sbostic return(error); 1147*45432Sbostic} 1148*45432Sbostic 1149*45432Sbostic/* 1150*45432Sbostic * unzap - initialize adapter but don't enable it. 1151*45432Sbostic * returns page number of next receive page to be used. 1152*45432Sbostic */ 1153*45432Sbosticunzap(addr) 1154*45432Sbostic register struct undevice *addr; 1155*45432Sbostic{ 1156*45432Sbostic register int next; 1157*45432Sbostic 1158*45432Sbostic MM_OUT(&addr->un_csr, 0); /* disable interrupts */ 1159*45432Sbostic MM_OUT(&addr->un_edlc.reset, RESET_ON); 1160*45432Sbostic /* set reset bit while init'ing */ 1161*45432Sbostic MM_OUT(&addr->un_edlc.rstat, RS_CLEAR); 1162*45432Sbostic MM_OUT(&addr->un_edlc.xstat, XS_CLEAR); 1163*45432Sbostic MM_OUT(&addr->un_edlc.rmask, 0); 1164*45432Sbostic MM_OUT(&addr->un_edlc.xmask, 0); 1165*45432Sbostic MM_OUT(&addr->un_edlc.rmode, RM_NORMAL); 1166*45432Sbostic /* 1167*45432Sbostic * the next line puts the transmitter in loopback mode so 1168*45432Sbostic * that a spurious packet is not sent when the reset bit is 1169*45432Sbostic * cleared. 1170*45432Sbostic */ 1171*45432Sbostic MM_OUT(&addr->un_edlc.tmode, TM_NORMAL - TM_LBC); 1172*45432Sbostic MM_OUT(&addr->un_edlc.reset, RESET_OFF); /* clear reset bit */ 1173*45432Sbostic /* 1174*45432Sbostic * clear the receive buffers. assign the value in the empty 1175*45432Sbostic * page pointer to the full page pointer and clear the packet 1176*45432Sbostic * available flag. 1177*45432Sbostic */ 1178*45432Sbostic next = MM_IN(&addr->un_fppepp) & UN_PAGE_MASK; 1179*45432Sbostic /* clears the IKSYDK flag */ 1180*45432Sbostic MM_OUT(&addr->un_fppepp, next); /* fpp = epp */ 1181*45432Sbostic UN_CLRPAV(addr); /* clear the PAV flag */ 1182*45432Sbostic MM_OUT(&addr->un_edlc.tmode, TM_NORMAL); 1183*45432Sbostic /* put transmitter in normal mode */ 1184*45432Sbostic DEBUGF(undebug & 0x2, printf("unzap: zzzzapped!\n");) 1185*45432Sbostic return(next); 1186*45432Sbostic} 1187*45432Sbostic 1188*45432Sbostic/* 1189*45432Sbostic * unupdatefpp - update adapter's full page pointer and clear packet available 1190*45432Sbostic * flag if appropriate 1191*45432Sbostic */ 1192*45432Sbosticunupdatefpp(addr, nextpage) 1193*45432Sbostic register struct undevice *addr; 1194*45432Sbostic register int nextpage; 1195*45432Sbostic{ 1196*45432Sbostic if (nextpage == /* EPP */ (MM_IN(&addr->un_fppepp) & UN_PAGE_MASK)) 1197*45432Sbostic UN_CLRPAV(addr); 1198*45432Sbostic MM_OUT(&addr->un_fppepp, nextpage); /* set FPP */ 1199*45432Sbostic} 1200*45432Sbostic 1201*45432Sbostic/* 1202*45432Sbostic * unbcopy - similar to bcopy but can deal with packets that wrap 1203*45432Sbostic * around from the high end of the adapter's receive buffer to the 1204*45432Sbostic * low end 1205*45432Sbostic */ 1206*45432Sbosticunbcopy(addr, from, to, len) 1207*45432Sbostic register struct undevice *addr; 1208*45432Sbostic register char *from; 1209*45432Sbostic register char *to; 1210*45432Sbostic register int len; 1211*45432Sbostic{ 1212*45432Sbostic register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE]; 1213*45432Sbostic register int n; 1214*45432Sbostic 1215*45432Sbostic if (from + len <= high_end){ 1216*45432Sbostic bcopyin(from, to, len); 1217*45432Sbostic } 1218*45432Sbostic else if (from >= high_end){ 1219*45432Sbostic from -= sizeof(addr->un_rcvbuf); 1220*45432Sbostic bcopyin(from, to, len); 1221*45432Sbostic } else { 1222*45432Sbostic n = high_end - from; 1223*45432Sbostic bcopyin(from, to, n); 1224*45432Sbostic to += n; 1225*45432Sbostic bcopyin((char *)addr->un_rcvbuf, to, len - n); 1226*45432Sbostic } 1227*45432Sbostic} 1228*45432Sbostic 1229*45432Sbostic/* 1230*45432Sbostic * ungetushortatoff - return the u_short at offset in the received packet, 1231*45432Sbostic * handling wrap-around in the receive buffer and conversion between network 1232*45432Sbostic * and host formats as necessary. 1233*45432Sbostic */ 1234*45432Sbosticu_short ungetushortatoff(addr, eh, off) 1235*45432Sbostic register struct undevice *addr; 1236*45432Sbostic register struct ether_header *eh; 1237*45432Sbostic register int off; 1238*45432Sbostic{ 1239*45432Sbostic register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE]; 1240*45432Sbostic register char *p; 1241*45432Sbostic 1242*45432Sbostic p = (caddr_t)(eh + 1) + off; 1243*45432Sbostic if (p >= high_end){ 1244*45432Sbostic p -= sizeof(addr->un_rcvbuf); 1245*45432Sbostic } 1246*45432Sbostic return(ntohs((u_short) MM_INW(p))); 1247*45432Sbostic} 1248*45432Sbostic 1249*45432Sbostic/* 1250*45432Sbostic * unprintethaddr - print an ethernet address 1251*45432Sbostic */ 1252*45432Sbosticunprintethaddr(p) 1253*45432Sbostic register char *p; 1254*45432Sbostic{ 1255*45432Sbostic register int i; 1256*45432Sbostic 1257*45432Sbostic for (i = 0; i < ETH_ADDR_SIZE; i++){ 1258*45432Sbostic if (i != 0) printf(":"); 1259*45432Sbostic printf("%x", *p++); 1260*45432Sbostic } 1261*45432Sbostic} 1262*45432Sbostic 1263*45432Sbostic#endif NUN > 0 1264