1: /*
   2:  * Copyright (c) 1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  *
   6:  *	@(#)if_en.c	1.3 (2.11BSD GTE) 1997/1/19
   7:  */
   8: 
   9: #include "en.h"
  10: #if NEN > 0
  11: 
  12: /*
  13:  * Xerox prototype (3 Mb) Ethernet interface driver.
  14:  */
  15: 
  16: #include "param.h"
  17: #include "systm.h"
  18: #include "mbuf.h"
  19: #include "buf.h"
  20: #include "domain.h"
  21: #include "protosw.h"
  22: #include "socket.h"
  23: #include "pdpuba/ubavar.h"
  24: #include "if_enreg.h"
  25: #include "netinet/in.h"
  26: #include "netinet/in_systm.h"
  27: #include "net/netisr.h"
  28: #include "net/if.h"
  29: #include "pdpif/if_en.h"
  30: #include "pdpif/if_uba.h"
  31: #include "netinet/ip.h"
  32: #include "netinet/ip_var.h"
  33: #include "netinet/in_var.h"
  34: #include "net/route.h"
  35: #include "errno.h"
  36: 
  37: #define ENMTU   (1024+512)
  38: #define ENMRU   (1024+512+16)       /* 16 is enough to receive trailer */
  39: 
  40: int enprobe(), enattach(), enrint(), enxint(), encollide();
  41: struct  uba_device *eninfo[NEN];
  42: u_short enstd[] = { 0 };
  43: struct  uba_driver endriver =
  44:     { enprobe, 0, enattach, 0, enstd, "en", eninfo };
  45: #define ENUNIT(x)   minor(x)
  46: 
  47: int eninit(),enoutput();
  48: 
  49: /*
  50:  * Ethernet software status per interface.
  51:  *
  52:  * Each interface is referenced by a network interface structure,
  53:  * es_if, which the routing code uses to locate the interface.
  54:  * This structure contains the output queue for the interface, its address, ...
  55:  * We also have, for each interface, a UBA interface structure, which
  56:  * contains information about the UNIBUS resources held by the interface:
  57:  * map registers, buffered data paths, etc.  Information is cached in this
  58:  * structure for use by the if_uba.c routines in running the interface
  59:  * efficiently.
  60:  */
  61: struct  en_softc {
  62:     struct  ifnet es_if;        /* network-visible interface */
  63:     struct  ifuba es_ifuba;     /* UNIBUS resources */
  64:     short   es_delay;       /* current output delay */
  65:     short   es_mask;        /* mask for current output delay */
  66:     short   es_lastx;       /* host last transmitted to */
  67:     short   es_oactive;     /* is output active? */
  68:     short   es_olen;        /* length of last output */
  69: } en_softc[NEN];
  70: 
  71: /*
  72:  * Do output DMA to determine interface presence and
  73:  * interrupt vector.  DMA is too short to disturb other hosts.
  74:  */
  75: enprobe(reg)
  76:     caddr_t reg;
  77: {
  78:     register int br, cvec;      /* r11, r10 value-result */
  79:     register struct endevice *addr = (struct endevice *)reg;
  80: 
  81: #ifndef pdp11
  82: #ifdef lint
  83:     br = 0; cvec = br; br = cvec;
  84:     enrint(0); enxint(0); encollide(0);
  85: #endif
  86:     addr->en_istat = 0;
  87:     addr->en_owc = -1;
  88:     addr->en_oba = 0;
  89:     addr->en_ostat = EN_IEN|EN_GO;
  90:     DELAY(100000L);
  91:     addr->en_ostat = 0;
  92: #ifdef ECHACK
  93:     br = 0x16;
  94: #endif
  95: #endif
  96:     return (1);
  97: }
  98: 
  99: /*
 100:  * Interface exists: make available by filling in network interface
 101:  * record.  System will initialize the interface when it is ready
 102:  * to accept packets.
 103:  */
 104: enattach(ui)
 105:     struct uba_device *ui;
 106: {
 107:     register struct en_softc *es = &en_softc[ui->ui_unit];
 108:     register struct sockaddr_in *sin;
 109: 
 110:     es->es_if.if_unit = ui->ui_unit;
 111:     es->es_if.if_name = "en";
 112:     es->es_if.if_mtu = ENMTU;
 113:     es->es_if.if_flags = IFF_BROADCAST;
 114:     es->es_if.if_init = eninit;
 115:     es->es_if.if_output = enoutput;
 116:     es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
 117:     if_attach(&es->es_if);
 118: }
 119: 
 120: /*
 121:  * Initialization of interface; clear recorded pending
 122:  * operations, and reinitialize UNIBUS usage.
 123:  */
 124: eninit(unit)
 125:     int unit;
 126: {
 127:     register struct en_softc *es = &en_softc[unit];
 128:     register struct uba_device *ui = eninfo[unit];
 129:     register struct endevice *addr;
 130:     int s;
 131: 
 132:     if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
 133:         sizeof (struct en_header), (int)btoc(ENMRU)) == 0) {
 134:         printf("en%d: can't initialize\n", unit);
 135:         es->es_if.if_flags &= ~IFF_UP;
 136:         return;
 137:     }
 138:     addr = (struct endevice *)ui->ui_addr;
 139:     addr->en_istat = addr->en_ostat = 0;
 140: 
 141:     /*
 142: 	 * Hang a receive and start any
 143: 	 * pending writes by faking a transmit complete.
 144: 	 */
 145:     s = splimp();
 146:     addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
 147:     addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
 148:     addr->en_istat = EN_IEN|EN_GO;
 149:     es->es_oactive = 1;
 150:     es->es_if.if_flags |= IFF_UP;
 151:     enxint(unit);
 152:     splx(s);
 153:     if_rtinit(&es->es_if, RTF_UP);
 154: }
 155: 
 156: int enalldelay = 0;
 157: int enlastdel = 50;
 158: int enlastmask = (~0) << 5;
 159: 
 160: /*
 161:  * Start or restart output on interface.
 162:  * If interface is already active, then this is a retransmit
 163:  * after a collision, and just restuff registers and delay.
 164:  * If interface is not already active, get another datagram
 165:  * to send off of the interface queue, and map it to the interface
 166:  * before starting the output.
 167:  */
 168: enstart(dev)
 169:     dev_t dev;
 170: {
 171:         int unit = ENUNIT(dev);
 172:     struct uba_device *ui = eninfo[unit];
 173:     register struct en_softc *es = &en_softc[unit];
 174:     register struct endevice *addr;
 175:     struct mbuf *m;
 176:     int dest;
 177: 
 178:     if (es->es_oactive)
 179:         goto restart;
 180: 
 181:     /*
 182: 	 * Not already active: dequeue another request
 183: 	 * and map it to the UNIBUS.  If no more requests,
 184: 	 * just return.
 185: 	 */
 186:     IF_DEQUEUE(&es->es_if.if_snd, m);
 187:     if (m == 0) {
 188:         es->es_oactive = 0;
 189:         return;
 190:     }
 191:     dest = mtod(m, struct en_header *)->en_dhost;
 192:     es->es_olen = if_wubaput(&es->es_ifuba, m);
 193: 
 194:     /*
 195: 	 * Ethernet cannot take back-to-back packets (no
 196: 	 * buffering in interface.  To help avoid overrunning
 197: 	 * receivers, enforce a small delay (about 1ms) in interface:
 198: 	 *	* between all packets when enalldelay
 199: 	 *	* whenever last packet was broadcast
 200: 	 *	* whenever this packet is to same host as last packet
 201: 	 */
 202:     if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
 203:         es->es_delay = enlastdel;
 204:         es->es_mask = enlastmask;
 205:     }
 206:     es->es_lastx = dest;
 207: 
 208: restart:
 209:     addr = (struct endevice *)ui->ui_addr;
 210:     addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
 211:     addr->en_odelay = es->es_delay;
 212:     addr->en_owc = -((es->es_olen + 1) >> 1);
 213:     addr->en_ostat = EN_IEN|EN_GO;
 214:     es->es_oactive = 1;
 215: }
 216: 
 217: /*
 218:  * Ethernet interface transmitter interrupt.
 219:  * Start another output if more data to send.
 220:  */
 221: enxint(unit)
 222:     int unit;
 223: {
 224:     register struct uba_device *ui = eninfo[unit];
 225:     register struct en_softc *es = &en_softc[unit];
 226:     register struct endevice *addr = (struct endevice *)ui->ui_addr;
 227: 
 228:     if (es->es_oactive == 0)
 229:         return;
 230:     if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
 231:         es->es_if.if_oerrors++;
 232:         endocoll(unit);
 233:         return;
 234:     }
 235:     es->es_if.if_opackets++;
 236:     es->es_oactive = 0;
 237:     es->es_delay = 0;
 238:     es->es_mask = ~0;
 239:     if (es->es_ifuba.ifu_xtofree) {
 240:         m_freem(es->es_ifuba.ifu_xtofree);
 241:         es->es_ifuba.ifu_xtofree = 0;
 242:     }
 243:     if (es->es_if.if_snd.ifq_head == 0) {
 244:         es->es_lastx = 256;     /* putatively illegal */
 245:         return;
 246:     }
 247:     enstart(unit);
 248: }
 249: 
 250: /*
 251:  * Collision on ethernet interface.  Do exponential
 252:  * backoff, and retransmit.  If have backed off all
 253:  * the way print warning diagnostic, and drop packet.
 254:  */
 255: encollide(unit)
 256:     int unit;
 257: {
 258:     struct en_softc *es = &en_softc[unit];
 259: 
 260:     es->es_if.if_collisions++;
 261:     if (es->es_oactive == 0)
 262:         return;
 263:     endocoll(unit);
 264: }
 265: 
 266: endocoll(unit)
 267:     int unit;
 268: {
 269:     register struct en_softc *es = &en_softc[unit];
 270: 
 271:     /*
 272: 	 * Es_mask is a 16 bit number with n low zero bits, with
 273: 	 * n the number of backoffs.  When es_mask is 0 we have
 274: 	 * backed off 16 times, and give up.
 275: 	 */
 276:     if (es->es_mask == 0) {
 277:         printf("en%d: send error\n", unit);
 278:         enxint(unit);
 279:         return;
 280:     }
 281:     /*
 282: 	 * Another backoff.
 283: 	 */
 284:     es->es_mask <<= 1;
 285:     es->es_delay = ffs(es->es_mask);
 286:     enstart(unit);
 287: }
 288: 
 289: #ifdef  notdef
 290: struct  sockaddr_pup pupsrc = { AF_PUP };
 291: struct  sockaddr_pup pupdst = { AF_PUP };
 292: struct  sockproto pupproto = { PF_PUP };
 293: #endif
 294: /*
 295:  * Ethernet interface receiver interrupt.
 296:  * If input error just drop packet.
 297:  * Otherwise purge input buffered data path and examine
 298:  * packet to determine type.  If can't determine length
 299:  * from type, then have to drop packet.  Othewise decapsulate
 300:  * packet based on type and pass to type specific higher-level
 301:  * input routine.
 302:  */
 303: enrint(unit)
 304:     int unit;
 305: {
 306:     register struct en_softc *es = &en_softc[unit];
 307:     struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
 308:     register struct en_header *en;
 309:         struct mbuf *m;
 310:     int len, plen; short resid;
 311:     register struct ifqueue *inq;
 312:     int off;
 313: 
 314:     es->es_if.if_ipackets++;
 315: 
 316:     if (addr->en_istat&EN_IERROR) {
 317:         es->es_if.if_ierrors++;
 318:         goto setup;
 319:     }
 320: 
 321:     /*
 322: 	 * Calculate input data length.
 323: 	 * Get pointer to ethernet header (in input buffer).
 324: 	 * Deal with trailer protocol: if type is PUP trailer
 325: 	 * get true type from first 16-bit word past data.
 326: 	 * Remember that type was trailer by setting off.
 327: 	 */
 328:     resid = addr->en_iwc;
 329:     if (resid)
 330:         resid |= 0176000;
 331:     len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
 332:     len -= sizeof (struct en_header);
 333:     if (len > ENMRU)
 334:         goto setup;         /* sanity */
 335:     en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_info);
 336: #define endataaddr(en, off, type)   ((type)(((caddr_t)((en)+1)+(off))))
 337:     if (en->en_type >= ENPUP_TRAIL &&
 338:         en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
 339:         off = (en->en_type - ENPUP_TRAIL) * 512;
 340:         if (off > ENMTU)
 341:             goto setup;     /* sanity */
 342:         en->en_type = *endataaddr(en, off, u_short *);
 343:         resid = *(endataaddr(en, off+2, u_short *));
 344:         if (off + resid > len)
 345:             goto setup;     /* sanity */
 346:         len = off + resid;
 347:     } else
 348:         off = 0;
 349:     if (len == 0)
 350:         goto setup;
 351:     /*
 352: 	 * Pull packet off interface.  Off is nonzero if packet
 353: 	 * has trailing header; if_rubaget will then force this header
 354: 	 * information to be at the front, but we still have to drop
 355: 	 * the type and length which are at the front of any trailer data.
 356: 	 */
 357:     m = if_rubaget(&es->es_ifuba, len, off, &es->es_if);
 358:     if (m == 0)
 359:         goto setup;
 360:     if (off) {
 361:         m->m_off += 2 * sizeof (u_short);
 362:         m->m_len -= 2 * sizeof (u_short);
 363:     }
 364:     switch (en->en_type) {
 365: 
 366: #ifdef INET
 367:     case ENPUP_IPTYPE:
 368:         schednetisr(NETISR_IP);
 369:         inq = &ipintrq;
 370:         break;
 371: #endif
 372: #ifdef PUP
 373:     case ENPUP_PUPTYPE: {
 374:         struct pup_header *pup = mtod(m, struct pup_header *);
 375: 
 376:         pupproto.sp_protocol = pup->pup_type;
 377:         pupdst.spup_addr = pup->pup_dport;
 378:         pupsrc.spup_addr = pup->pup_sport;
 379:         raw_input(m, &pupproto, (struct sockaddr *)&pupsrc,
 380:           (struct sockaddr *)&pupdst);
 381:         goto setup;
 382:     }
 383: #endif
 384:     default:
 385:         m_freem(m);
 386:         goto setup;
 387:     }
 388: 
 389:     if (IF_QFULL(inq)) {
 390:         IF_DROP(inq);
 391:         m_freem(m);
 392:     } else
 393:         IF_ENQUEUE(inq, m);
 394: 
 395: setup:
 396:     /*
 397: 	 * Reset for next packet.
 398: 	 */
 399:     addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
 400:     addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
 401:     addr->en_istat = EN_IEN|EN_GO;
 402: }
 403: 
 404: /*
 405:  * Ethernet output routine.
 406:  * Encapsulate a packet of type family for the local net.
 407:  * Use trailer local net encapsulation if enough data in first
 408:  * packet leaves a multiple of 512 bytes of data in remainder.
 409:  */
 410: enoutput(ifp, m0, dst)
 411:     struct ifnet *ifp;
 412:     struct mbuf *m0;
 413:     struct sockaddr *dst;
 414: {
 415:     int type, dest, s, error;
 416:     register struct mbuf *m = m0;
 417:     register struct en_header *en;
 418:     register int off;
 419: 
 420:     switch (dst->sa_family) {
 421: 
 422: #ifdef INET
 423:     case AF_INET:
 424:         dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
 425:         if (dest & 0x00ffff00) {
 426:             error = EPERM;      /* ??? */
 427:             goto bad;
 428:         }
 429:         dest = (dest >> 24) & 0xff;
 430:         off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
 431:         if (off > 0 && (off & 0x1ff) == 0 &&
 432:             m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
 433:             type = ENPUP_TRAIL + (off>>9);
 434:             m->m_off -= 2 * sizeof (u_short);
 435:             m->m_len += 2 * sizeof (u_short);
 436:             *mtod(m, u_short *) = ENPUP_IPTYPE;
 437:             *(mtod(m, u_short *) + 1) = m->m_len;
 438:             goto gottrailertype;
 439:         }
 440:         type = ENPUP_IPTYPE;
 441:         off = 0;
 442:         goto gottype;
 443: #endif
 444: #ifdef PUP
 445:     case AF_PUP:
 446:         dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host;
 447:         type = ENPUP_PUPTYPE;
 448:         off = 0;
 449:         goto gottype;
 450: #endif
 451: 
 452:     default:
 453:         printf("en%d: can't handle af%d\n", ifp->if_unit,
 454:             dst->sa_family);
 455:         error = EAFNOSUPPORT;
 456:         goto bad;
 457:     }
 458: 
 459: gottrailertype:
 460:     /*
 461: 	 * Packet to be sent as trailer: move first packet
 462: 	 * (control information) to end of chain.
 463: 	 */
 464:     while (m->m_next)
 465:         m = m->m_next;
 466:     m->m_next = m0;
 467:     m = m0->m_next;
 468:     m0->m_next = 0;
 469:     m0 = m;
 470: 
 471: gottype:
 472:     /*
 473: 	 * Add local net header.  If no space in first mbuf,
 474: 	 * allocate another.
 475: 	 */
 476:     if (m->m_off > MMAXOFF ||
 477:         MMINOFF + sizeof (struct en_header) > m->m_off) {
 478:         m = m_get(M_DONTWAIT);
 479:         if (m == 0) {
 480:             error = ENOBUFS;
 481:             goto bad;
 482:         }
 483:         m->m_next = m0;
 484:         m->m_off = MMINOFF;
 485:         m->m_len = sizeof (struct en_header);
 486:     } else {
 487:         m->m_off -= sizeof (struct en_header);
 488:         m->m_len += sizeof (struct en_header);
 489:     }
 490:     en = mtod(m, struct en_header *);
 491:     en->en_dhost = dest;
 492:     en->en_type = htons((u_short)type);
 493: 
 494:     /*
 495: 	 * Queue message on interface, and start output if interface
 496: 	 * not yet active.
 497: 	 */
 498:     s = splimp();
 499:     if (IF_QFULL(&ifp->if_snd)) {
 500:         IF_DROP(&ifp->if_snd);
 501:         error = ENOBUFS;
 502:         goto qfull;
 503:     }
 504:     IF_ENQUEUE(&ifp->if_snd, m);
 505:     if (en_softc[ifp->if_unit].es_oactive == 0)
 506:         enstart(ifp->if_unit);
 507:     splx(s);
 508:     return (0);
 509: qfull:
 510:     m0 = m;
 511:     splx(s);
 512: bad:
 513:     m_freem(m0);
 514:     return (error);
 515: }
 516: #endif	NEN > 0

Defined functions

enattach defined in line 104; used 2 times
encollide defined in line 255; used 2 times
endocoll defined in line 266; used 2 times
eninit defined in line 124; used 2 times
enoutput defined in line 410; used 2 times
enprobe defined in line 75; used 2 times
enrint defined in line 303; used 2 times
enstart defined in line 168; used 3 times
enxint defined in line 221; used 4 times

Defined variables

en_softc defined in line 69; used 8 times
enalldelay defined in line 156; used 1 times
endriver defined in line 43; never used
eninfo defined in line 41; used 5 times
enlastdel defined in line 157; used 1 times
enlastmask defined in line 158; used 1 times
enstd defined in line 42; used 1 times
  • in line 44
pupdst defined in line 291; used 2 times
pupproto defined in line 292; used 2 times
pupsrc defined in line 290; used 2 times

Defined struct's

en_softc defined in line 61; used 14 times

Defined macros

ENMRU defined in line 38; used 5 times
ENMTU defined in line 37; used 2 times
ENUNIT defined in line 45; used 1 times
endataaddr defined in line 336; used 2 times
Last modified: 1997-01-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4616
Valid CSS Valid XHTML 1.0 Strict