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