1 /* 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)if_imp.c 7.14 (Berkeley) 10/11/92 8 */ 9 10 #include "imp.h" 11 #if NIMP > 0 12 /* 13 * ARPANET IMP (PSN) interface driver. 14 * 15 * The IMP-host protocol (AHIP) is handled here, leaving 16 * hardware specifics to the lower level interface driver. 17 */ 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/mbuf.h> 21 #include <sys/buf.h> 22 #include <sys/protosw.h> 23 #include <sys/socket.h> 24 #include <sys/time.h> 25 #include <sys/kernel.h> 26 #include <sys/errno.h> 27 #include <sys/ioctl.h> 28 #include <sys/syslog.h> 29 30 #include <machine/mtpr.h> 31 32 #include <net/if.h> 33 #include <net/netisr.h> 34 #include <netinet/in.h> 35 #include <netinet/in_systm.h> 36 #include <netinet/in_var.h> 37 #include <netinet/ip.h> 38 #include <netinet/ip_var.h> 39 40 #define IMPMESSAGES 41 /* define IMPLEADERS here to get leader printing code */ 42 #include <netimp/if_imp.h> 43 #include <netimp/if_imphost.h> 44 45 struct imp_softc imp_softc[NIMP]; 46 #ifndef lint 47 int nimp = NIMP; /* for netstat */ 48 #endif 49 struct ifqueue impintrq; 50 int impqmaxlen = IFQ_MAXLEN; 51 int imphqlen = 12 + IMP_MAXHOSTMSG; /* max packets to queue per host */ 52 53 int imppri = LOG_ERR; 54 #ifdef IMPLEADERS 55 int impprintfs = 0; 56 #endif 57 #ifdef IMPINIT 58 int imptraceinit = 0; 59 #endif 60 61 62 #define HOSTDEADTIMER (30 * PR_SLOWHZ) /* How long to wait when down */ 63 64 int impdown(), impinit(), impioctl(), impoutput(), imptimo(); 65 66 /* 67 * IMP attach routine. Called from hardware device attach routine 68 * at configuration time with a pointer to the device structure. 69 * Sets up local state and returns pointer to base of ifnet+impcb 70 * structures. This is then used by the device's attach routine 71 * set up its back pointers. 72 */ 73 struct imp_softc * 74 impattach(hwname, hwunit, reset) 75 char *hwname; 76 int hwunit; 77 int (*reset)(); 78 { 79 struct imp_softc *sc; 80 register struct ifnet *ifp; 81 static int impunit; 82 83 #ifdef lint 84 impintr(); 85 #endif 86 if (impunit >= NIMP) { 87 printf("imp%d: not configured\n", impunit++); 88 return (0); 89 } 90 sc = &imp_softc[impunit]; 91 ifp = &sc->imp_if; 92 sc->imp_cb.ic_hwname = hwname; 93 sc->imp_cb.ic_hwunit = hwunit; 94 ifp->if_unit = impunit; 95 ifp->if_name = "imp"; 96 ifp->if_mtu = IMPMTU - sizeof(struct imp_leader); 97 ifp->if_reset = reset; 98 ifp->if_init = impinit; 99 ifp->if_ioctl = impioctl; 100 ifp->if_output = impoutput; 101 ifp->if_watchdog = imptimo; 102 if_attach(ifp); 103 impunit++; 104 return (sc); 105 } 106 107 /* 108 * IMP initialization routine: call hardware module to 109 * setup resources, init state and get ready for 110 * NOOPs the IMP should send us, and that we want to drop. 111 */ 112 impinit(unit) 113 int unit; 114 { 115 int s; 116 register struct imp_softc *sc = &imp_softc[unit]; 117 118 if (sc->imp_if.if_addrlist == 0) 119 return; 120 s = splimp(); 121 #ifdef IMPINIT 122 if (imptraceinit) 123 log(imppri, "impinit\n"); 124 #endif 125 sc->imp_state = IMPS_WINIT; 126 if ((*sc->imp_cb.ic_init)(sc->imp_cb.ic_hwunit) == 0) 127 sc->imp_if.if_flags &= ~IFF_UP; 128 impintrq.ifq_maxlen = impqmaxlen; 129 splx(s); 130 } 131 132 /* 133 * ARPAnet 1822/AHIP input routine. 134 * Called from hardware input interrupt routine to handle 1822 135 * IMP-host messages. Data messages are passed to higher-level 136 * protocol processors on the basis of link number. 137 * Other type messages (control) are handled here. 138 */ 139 impinput(unit, m) 140 int unit; 141 register struct mbuf *m; 142 { 143 register struct control_leader *cp; 144 #define ip ((struct imp_leader *)cp) 145 register struct imp_softc *sc = &imp_softc[unit]; 146 struct ifnet *ifp; 147 register struct host *hp; 148 register struct ifqueue *inq; 149 struct sockaddr_in *sin; 150 int s; 151 152 /* 153 * Pull the interface pointer out of the mbuf 154 * and save for later; adjust mbuf to look at rest of data. 155 */ 156 if ((m->m_flags && M_PKTHDR) == 0) 157 panic("No header in impinput"); 158 ifp = m->m_pkthdr.rcvif; 159 /* verify leader length. */ 160 if (m->m_len < sizeof(struct control_leader) && 161 (m = m_pullup(m, sizeof(struct control_leader))) == 0) 162 return; 163 cp = mtod(m, struct control_leader *); 164 if (cp->dl_mtype == IMPTYPE_DATA && 165 m->m_len < sizeof(struct imp_leader)) { 166 if ((m = m_pullup(m, sizeof(struct imp_leader))) == 0) 167 return; 168 cp = mtod(m, struct control_leader *); 169 } 170 #ifdef IMPLEADERS 171 if (impprintfs) 172 printleader("impinput", ip); 173 #endif 174 inq = &impintrq; 175 176 /* check leader type */ 177 if (cp->dl_format != IMP_NFF) { 178 /* 179 * We get 1822L NOOPs and RESET 180 * at initialization. 181 */ 182 #ifdef IMPINIT 183 if (imptraceinit) 184 log(imppri, "input, format %x mtype %d\n", 185 cp->dl_format, cp->dl_mtype); 186 #endif 187 if (cp->dl_format != IMP_1822L_I2H || 188 (cp->dl_mtype != IMPTYPE_NOOP && 189 cp->dl_mtype != IMPTYPE_RESET)) { 190 sc->imp_garbage++; 191 sc->imp_if.if_collisions++; /* XXX */ 192 } 193 } else switch (cp->dl_mtype) { 194 195 case IMPTYPE_DATA: 196 /* 197 * Data for a protocol. Dispatch to the appropriate 198 * protocol routine (running at software interrupt). 199 * If this isn't a raw interface, advance pointer 200 * into mbuf past leader. 201 */ 202 switch (cp->dl_link) { 203 204 case IMPLINK_IP: 205 m->m_len -= sizeof(struct imp_leader); 206 if (m->m_flags & M_PKTHDR) 207 m->m_pkthdr.len -= sizeof(struct imp_leader); 208 m->m_data += sizeof(struct imp_leader); 209 schednetisr(NETISR_IP); 210 inq = &ipintrq; 211 break; 212 213 default: 214 break; 215 } 216 break; 217 218 /* 219 * IMP leader error. Reset the IMP and discard the packet. 220 */ 221 case IMPTYPE_BADLEADER: 222 /* 223 * According to 1822 document, this message 224 * will be generated in response to the 225 * first noop sent to the IMP after 226 * the host resets the IMP interface. 227 */ 228 #ifdef IMPINIT 229 if (imptraceinit) 230 log(imppri, "badleader\n"); 231 #endif 232 if (sc->imp_state != IMPS_INIT) { 233 impmsg(sc, "leader error"); 234 sc->imp_msgready = 0; 235 hostreset(unit); 236 impnoops(sc); 237 sc->imp_garbage++; 238 } 239 break; 240 241 /* 242 * IMP going down. Print message, and if not immediate, 243 * set off a timer to insure things will be reset at the 244 * appropriate time. 245 */ 246 case IMPTYPE_DOWN: 247 { int type, when; 248 249 type = cp->dl_link & IMP_DMASK; 250 when = (cp->dl_link & IMPDOWN_WHENMASK) >> IMPDOWN_WHENSHIFT; 251 #ifdef IMPINIT 252 if (imptraceinit) 253 log(imppri, "input DOWN %s %d\n", 254 impmessage[type], when * IMPDOWN_WHENUNIT); 255 #endif 256 if (type != IMPDOWN_GOING && when) 257 impmsg(sc, "going down %s in %d minutes", 258 (u_int)impmessage[type], when * IMPDOWN_WHENUNIT); 259 else 260 impmsg(sc, "going down %s", (u_int)impmessage[type]); 261 if (sc->imp_state != IMPS_UP) 262 break; 263 if (type == IMPDOWN_GOING) { 264 sc->imp_state = IMPS_GOINGDOWN; 265 timeout(impdown, (caddr_t)sc, IMPTV_DOWN * hz); 266 } else if (when == 0) 267 sc->imp_state = IMPS_WINIT; 268 sc->imp_dropcnt = 0; 269 break; 270 } 271 272 /* 273 * A NOP, usually seen during the initialization sequence. 274 * Compare the local address with that in the message. 275 * Reset the local address notion if it doesn't match. 276 */ 277 case IMPTYPE_NOOP: 278 #ifdef IMPINIT 279 if (imptraceinit) 280 log(imppri, "noop\n"); 281 #endif 282 if (sc->imp_state == IMPS_WINIT) { 283 sc->imp_dropcnt = 0; 284 impnoops(sc); 285 sc->imp_state = IMPS_INIT; 286 } 287 sc->imp_dropcnt++; 288 if (sc->imp_state == IMPS_INIT && cp->dl_imp != 0) { 289 struct in_addr leader_addr; 290 291 sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr; 292 imp_leader_to_addr(&leader_addr, cp, &sc->imp_if); 293 if (sin->sin_addr.s_addr != leader_addr.s_addr) { 294 impmsg(sc, "address reset to x%x (%d/%d)", 295 ntohl(leader_addr.s_addr), 296 (u_int)cp->dl_host, 297 ntohs(cp->dl_imp)); 298 sin->sin_addr.s_addr = leader_addr.s_addr; 299 } 300 } 301 break; 302 303 /* 304 * RFNM or INCOMPLETE message, decrement rfnm count 305 * and prepare to send next message. 306 * If the rfnm allows another queued 307 * message to be sent, bump msgready 308 * and start IMP if idle. 309 * We could pass incomplete's up to the next level, 310 * but this currently isn't needed. 311 * Pass "bad" incompletes and rfnms to the raw socket. 312 */ 313 case IMPTYPE_INCOMPLETE: 314 sc->imp_incomplete++; 315 /* FALL THROUGH */ 316 case IMPTYPE_RFNM: 317 if ((hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, 318 unit)) == 0 || hp->h_rfnm == 0) { 319 sc->imp_badrfnm++; 320 if (hp) 321 hostfree(hp); 322 break; 323 } 324 imprestarthost(sc, hp); 325 if (cp->dl_mtype == IMPTYPE_RFNM) 326 goto drop; 327 break; 328 329 /* 330 * Host or IMP can't be reached. Flush any packets 331 * awaiting transmission and release the host structure. 332 * Enqueue for notifying protocols at software interrupt time. 333 */ 334 case IMPTYPE_HOSTDEAD: 335 case IMPTYPE_HOSTUNREACH: 336 if (hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, unit)) { 337 hp->h_flags |= (1 << (int)cp->dl_mtype); 338 sc->imp_msgready -= 339 MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm); 340 hp->h_rfnm = 0; 341 hostflush(hp); 342 hp->h_timer = HOSTDEADTIMER; 343 } 344 break; 345 346 /* 347 * Error in data. Clear RFNM status for this host and send 348 * noops to the IMP to clear the interface. 349 */ 350 case IMPTYPE_BADDATA: 351 impmsg(sc, "data error"); 352 if (hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, unit)) { 353 sc->imp_msgready -= 354 MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm); 355 if (hp->h_rfnm) 356 hostrelease(hp); 357 else 358 hostfree(hp); 359 } 360 impnoops(sc); 361 break; 362 363 /* 364 * Interface reset. 365 */ 366 case IMPTYPE_RESET: 367 #ifdef IMPINIT 368 if (imptraceinit) 369 log(imppri, "reset complete\n"); 370 #endif 371 if (sc->imp_state != IMPS_INIT) { 372 impmsg(sc, "interface reset"); 373 impnoops(sc); 374 } 375 /* clear RFNM counts */ 376 sc->imp_msgready = 0; 377 hostreset(unit); 378 if (sc->imp_state != IMPS_DOWN) { 379 sc->imp_state = IMPS_UP; 380 sc->imp_if.if_flags |= IFF_UP; 381 #ifdef IMPINIT 382 if (imptraceinit) 383 log(imppri, "IMP UP\n"); 384 #endif 385 } 386 break; 387 388 default: 389 sc->imp_garbage++; 390 sc->imp_if.if_collisions++; /* XXX */ 391 break; 392 } 393 394 if (inq == &impintrq) 395 schednetisr(NETISR_IMP); 396 s = splimp(); 397 if (!IF_QFULL(inq)) { 398 IF_ENQUEUE(inq, m); 399 splx(s); 400 return; 401 } 402 splx(s); 403 IF_DROP(inq); 404 drop: 405 m_freem(m); 406 #undef ip 407 } 408 409 /* 410 * Bring the IMP down after notification. 411 */ 412 impdown(sc) 413 struct imp_softc *sc; 414 { 415 int s = splimp(); 416 417 if (sc->imp_state == IMPS_GOINGDOWN) { 418 sc->imp_state = IMPS_WINIT; 419 impmsg(sc, "marked down"); 420 sc->imp_msgready = 0; 421 hostreset(sc->imp_if.if_unit); 422 if_down(&sc->imp_if); 423 } 424 #ifdef IMPINIT 425 else if (imptraceinit) 426 log(imppri, "impdown, state now %d (ignored)\n", sc->imp_state); 427 #endif 428 splx(s); 429 } 430 431 /*VARARGS2*/ 432 impmsg(sc, fmt, a1) 433 struct imp_softc *sc; 434 char *fmt; 435 u_int a1; 436 { 437 438 log(imppri, "imp%d: %r\n", sc->imp_if.if_unit, fmt, &a1); 439 } 440 441 struct sockproto impproto = { PF_IMPLINK }; 442 struct sockaddr_in impdst = { sizeof (impdst), AF_INET }; 443 struct sockaddr_in impsrc = { sizeof (impsrc), AF_INET }; 444 445 /* 446 * Pick up the IMP "error" messages enqueued earlier, 447 * passing these up to the higher level protocol 448 * and the raw interface. 449 */ 450 impintr() 451 { 452 register struct mbuf *m; 453 register struct control_leader *cp; 454 struct ifnet *ifp; 455 int s, code; 456 457 for (;;) { 458 s = splimp(); 459 IF_DEQUEUEIF(&impintrq, m, ifp); 460 splx(s); 461 if (m == 0) 462 return; 463 464 cp = mtod(m, struct control_leader *); 465 imp_leader_to_addr(&impsrc.sin_addr, cp, ifp); 466 impproto.sp_protocol = cp->dl_link; 467 impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr; 468 469 if (cp->dl_mtype == IMPTYPE_HOSTDEAD || 470 cp->dl_mtype == IMPTYPE_HOSTUNREACH) { 471 code = (cp->dl_mtype == IMPTYPE_HOSTDEAD) ? 472 PRC_HOSTDEAD : PRC_UNREACH_HOST; 473 switch (cp->dl_link) { 474 475 case IMPLINK_IP: 476 pfctlinput(code, (struct sockaddr *)&impsrc); 477 break; 478 default: 479 raw_ctlinput(code, (struct sockaddr *)&impsrc); 480 break; 481 } 482 } 483 484 raw_input(m, &impproto, (struct sockaddr *)&impsrc, 485 (struct sockaddr *)&impdst); 486 } 487 } 488 489 /* 490 * ARPAnet 1822 output routine. 491 * Called from higher level protocol routines to set up messages for 492 * transmission to the imp. Sets up the header and calls impsnd to 493 * enqueue the message for this IMP's hardware driver. 494 */ 495 impoutput(ifp, m0, dst) 496 register struct ifnet *ifp; 497 struct mbuf *m0; 498 struct sockaddr *dst; 499 { 500 register struct imp_leader *imp; 501 register struct mbuf *m = m0; 502 caddr_t pkt = mtod(m, caddr_t); 503 int error = 0; 504 505 /* 506 * Don't even try if the IMP is unavailable. 507 */ 508 if (!IMPS_RUNNING(imp_softc[ifp->if_unit].imp_state)) { 509 error = ENETDOWN; 510 goto drop; 511 } 512 513 /* 514 * If AF_IMPLINK, leader exists; just send. 515 * Otherwise, construct leader according to address family. 516 */ 517 if (dst->sa_family != AF_IMPLINK) { 518 /* 519 * Add IMP leader. If there's not enough space in the 520 * first mbuf, allocate another. If that should fail, we 521 * drop this sucker. 522 */ 523 M_PREPEND(m, sizeof(struct imp_leadr), M_DONTWAIT); 524 imp = mtod(m, struct imp_leader *); 525 imp->il_format = IMP_NFF; 526 imp->il_mtype = IMPTYPE_DATA; 527 imp->il_flags = 0; 528 imp->il_htype = 0; 529 imp->il_subtype = 0; 530 531 switch (dst->sa_family) { 532 533 case AF_INET: 534 imp->il_link = IMPLINK_IP; 535 imp_addr_to_leader((struct control_leader *)imp, 536 ((struct sockaddr_in *)dst)->sin_addr.s_addr); 537 imp->il_length = htons(ntohs((u_short) 538 ((struct ip *)pkt)->ip_len) << 3); 539 break; 540 541 default: 542 printf("imp%d: can't handle af%d\n", ifp->if_unit, 543 dst->sa_family); 544 error = EAFNOSUPPORT; 545 m0 = m; 546 goto drop; 547 } 548 } 549 return (impsnd(ifp, m)); 550 drop: 551 m_freem(m0); 552 return (error); 553 } 554 555 /* 556 * Put a message on an interface's output queue. 557 * Perform RFNM counting: no more than 8 message may be 558 * in flight to any one host. 559 */ 560 impsnd(ifp, m) 561 struct ifnet *ifp; 562 struct mbuf *m; 563 { 564 register struct control_leader *imp; 565 register struct host *hp; 566 register struct imp_softc *sc = &imp_softc[ifp->if_unit]; 567 int s, error = 0; 568 569 imp = mtod(m, struct control_leader *); 570 571 /* 572 * Do RFNM counting for data messages 573 * (no more than 8 outstanding to any host). 574 * Queue data messages per host if 8 are already outstanding 575 * or if the hardware interface is already doing output. 576 * Increment imp_msgready if the message could be sent now, 577 * but must be queued because the imp output is busy. 578 */ 579 s = splimp(); 580 if (imp->dl_mtype == IMPTYPE_DATA) { 581 hp = hostenter((int)imp->dl_imp, (int)imp->dl_host, 582 ifp->if_unit); 583 if (hp) { 584 if (hp->h_flags & (HF_DEAD|HF_UNREACH)) 585 error = hp->h_flags & HF_DEAD ? 586 EHOSTDOWN : EHOSTUNREACH; 587 else if (hp->h_rfnm < IMP_MAXHOSTMSG && 588 sc->imp_cb.ic_oactive == 0) { 589 /* 590 * Send without queuing; 591 * adjust rfnm count and timer. 592 */ 593 if (hp->h_rfnm++ == 0) 594 hp->h_timer = RFNMTIMER; 595 goto send; 596 } else if (hp->h_rfnm + hp->h_qcnt < imphqlen) { 597 HOST_ENQUE(hp, m); 598 if (hp->h_rfnm + hp->h_qcnt <= IMP_MAXHOSTMSG) 599 sc->imp_msgready++; 600 } else { 601 error = ENOBUFS; 602 IF_DROP(&ifp->if_snd); 603 } 604 } else 605 error = ENOBUFS; 606 } else if (sc->imp_cb.ic_oactive == 0) 607 goto send; 608 else 609 IF_ENQUEUE(&ifp->if_snd, m); 610 611 splx(s); 612 if (error) 613 m_freem(m); 614 return (error); 615 616 send: 617 sc->imp_if.if_timer = IMP_OTIMER; 618 (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m); 619 splx(s); 620 return (0); 621 } 622 623 /* 624 * Start another output operation on IMP; called from hardware 625 * transmit-complete interrupt routine at splimp or from imp routines 626 * when output is not in progress. If there are any packets on shared 627 * output queue, send them, otherwise send the next data packet for a host. 628 * Host data packets are sent round-robin based on destination by walking 629 * the host list. 630 */ 631 impstart(sc) 632 register struct imp_softc *sc; 633 { 634 register struct mbuf *m; 635 int first = 1; /* XXX */ 636 register struct host *hp; 637 int index; 638 639 IF_DEQUEUE(&sc->imp_if.if_snd, m); 640 if (m) { 641 sc->imp_if.if_timer = IMP_OTIMER; 642 (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m); 643 return; 644 } 645 if (sc->imp_msgready) { 646 if ((m = sc->imp_hostq) == 0 && (m = sc->imp_hosts) == 0) 647 panic("imp msgready"); 648 index = sc->imp_hostent; 649 for (hp = &mtod(m, struct hmbuf *)->hm_hosts[index]; ; 650 hp++, index++) { 651 if (index >= HPMBUF) { 652 if ((m = m->m_next) == 0) 653 m = sc->imp_hosts; 654 index = 0; 655 hp = mtod(m, struct hmbuf *)->hm_hosts; 656 first = 0; /* XXX */ 657 } 658 if (hp->h_qcnt && hp->h_rfnm < IMP_MAXHOSTMSG) { 659 /* 660 * Found host entry with another message 661 * to send. Deliver it to the IMP. 662 * Start with succeeding host next time. 663 */ 664 impstarthost(sc, hp); 665 sc->imp_hostq = m; 666 sc->imp_hostent = index + 1; 667 return; 668 } 669 if (m == sc->imp_hostq && !first && 670 index + 1 >= sc->imp_hostent) { /* XXX */ 671 log(imppri, "imp: can't find %d msgready\n", 672 sc->imp_msgready); 673 sc->imp_msgready = 0; 674 break; 675 } 676 } 677 } 678 sc->imp_if.if_timer = 0; 679 } 680 681 /* 682 * Restart output for a host that has received a RFNM 683 * or incomplete or has timed out while waiting for a RFNM. 684 * Must be called at splimp. 685 */ 686 imprestarthost(sc, hp) 687 register struct imp_softc *sc; 688 struct host *hp; 689 { 690 691 if (--hp->h_rfnm > 0) 692 hp->h_timer = RFNMTIMER; 693 /* 694 * If the RFNM moved a queued message into the window, 695 * update msgready and start IMP if idle. 696 */ 697 if (hp->h_qcnt > IMP_MAXHOSTMSG - 1 - hp->h_rfnm) { 698 sc->imp_msgready++; 699 if (sc->imp_cb.ic_oactive == 0) 700 impstarthost(sc, hp); 701 } 702 if (hp->h_rfnm == 0 && hp->h_qcnt == 0) 703 hostidle(hp); 704 } 705 706 /* 707 * Send the next message queued for a host 708 * when ready to send another message to the IMP. 709 * Called only when output is not in progress. 710 * Bump RFNM counter and start RFNM timer 711 * when we send the message to the IMP. 712 * Must be called at splimp. 713 */ 714 impstarthost(sc, hp) 715 register struct imp_softc *sc; 716 register struct host *hp; 717 { 718 struct mbuf *m; 719 720 if (hp->h_rfnm++ == 0) 721 hp->h_timer = RFNMTIMER; 722 HOST_DEQUE(hp, m); 723 sc->imp_if.if_timer = IMP_OTIMER; 724 (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m); 725 sc->imp_msgready--; 726 } 727 728 /* 729 * "Watchdog" timeout. When the output timer expires, 730 * we assume we have been blocked by the imp. 731 * No need to restart, just collect statistics. 732 */ 733 imptimo(unit) 734 int unit; 735 { 736 737 imp_softc[unit].imp_block++; 738 } 739 740 /* 741 * Put three 1822 NOOPs at the head of the output queue. 742 * Part of host-IMP initialization procedure. 743 * (Should return success/failure, but noone knows 744 * what to do with this, so why bother?) 745 * This routine is always called at splimp, so we don't 746 * protect the call to IF_PREPEND. 747 */ 748 impnoops(sc) 749 register struct imp_softc *sc; 750 { 751 register i; 752 register struct mbuf *m; 753 register struct control_leader *cp; 754 755 #ifdef IMPINIT 756 if (imptraceinit) 757 log(imppri, "impnoops\n"); 758 #endif 759 for (i = 0; i < IMP_NOOPCNT; i++) { 760 if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0) 761 return; 762 m->m_len = sizeof(struct control_leader); 763 cp = mtod(m, struct control_leader *); 764 cp->dl_format = IMP_NFF; 765 cp->dl_link = i; 766 cp->dl_mtype = IMPTYPE_NOOP; 767 IF_PREPEND(&sc->imp_if.if_snd, m); 768 } 769 if (sc->imp_cb.ic_oactive == 0) 770 impstart(sc); 771 } 772 773 /* 774 * Process an ioctl request. 775 */ 776 impioctl(ifp, cmd, data) 777 register struct ifnet *ifp; 778 int cmd; 779 caddr_t data; 780 { 781 struct ifaddr *ifa = (struct ifaddr *) data; 782 int s = splimp(), error = 0; 783 #define sc ((struct imp_softc *)ifp) 784 785 switch (cmd) { 786 787 case SIOCSIFADDR: 788 if (ifa->ifa_addr.sa_family != AF_INET) { 789 error = EINVAL; 790 break; 791 } 792 if ((ifp->if_flags & IFF_UP) == 0) 793 impinit(ifp->if_unit); 794 break; 795 796 case SIOCSIFFLAGS: 797 if ((ifp->if_flags & IFF_UP) == 0 && 798 sc->imp_state != IMPS_DOWN) { 799 if (sc->imp_cb.ic_down && 800 (*sc->imp_cb.ic_down)(sc->imp_cb.ic_hwunit)) { 801 sc->imp_state = IMPS_DOWN; 802 sc->imp_msgready = 0; 803 hostreset(ifp->if_unit); 804 if_down(ifp); 805 } 806 } else if (ifp->if_flags & IFF_UP && sc->imp_state == IMPS_DOWN) 807 impinit(ifp->if_unit); 808 break; 809 810 default: 811 error = EINVAL; 812 break; 813 } 814 splx(s); 815 return (error); 816 } 817 818 #ifdef IMPLEADERS 819 printleader(routine, ip) 820 char *routine; 821 register struct imp_leader *ip; 822 { 823 printf("%s: ", routine); 824 printbyte((char *)ip, 12); 825 printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network, 826 ip->il_flags); 827 if (ip->il_mtype <= IMPTYPE_READY) 828 printf("%s,", impleaders[ip->il_mtype]); 829 else 830 printf("%x,", ip->il_mtype); 831 printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host, 832 ntohs(ip->il_imp)); 833 if (ip->il_link == IMPLINK_IP) 834 printf("ip,"); 835 else 836 printf("%x,", ip->il_link); 837 printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3); 838 } 839 840 printbyte(cp, n) 841 register char *cp; 842 int n; 843 { 844 register i, j, c; 845 846 for (i=0; i<n; i++) { 847 c = *cp++; 848 for (j=0; j<2; j++) 849 putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0); 850 putchar(' ', 0); 851 } 852 putchar('\n', 0); 853 } 854 #endif 855 856 /* 857 * Routine to convert from IMP Leader to InterNet Address. 858 * 859 * This procedure is necessary because IMPs may be assigned Class A, B, or C 860 * network numbers, but only have 8 bits in the leader to reflect the 861 * IMP "network number". The strategy is to take the network number from 862 * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers 863 * from the leader. 864 * 865 * There is no support for "Logical Hosts". 866 * 867 * Class A: Net.Host.0.Imp 868 * Class B: Net.net.Host.Imp 869 * Class C: Net.net.net.(Host4|Imp4) 870 */ 871 imp_leader_to_addr(ap, cp, ifp) 872 struct in_addr *ap; 873 register struct control_leader *cp; 874 struct ifnet *ifp; 875 { 876 register u_long final; 877 register struct sockaddr_in *sin; 878 int imp = ntohs(cp->dl_imp); 879 880 sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr); 881 final = ntohl(sin->sin_addr.s_addr); 882 883 if (IN_CLASSA(final)) { 884 final &= IN_CLASSA_NET; 885 final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<16); 886 } else if (IN_CLASSB(final)) { 887 final &= IN_CLASSB_NET; 888 final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<8); 889 } else { 890 final &= IN_CLASSC_NET; 891 final |= (imp & 0x0F) | ((cp->dl_host & 0x0F)<<4); 892 } 893 ap->s_addr = htonl(final); 894 } 895 896 /* 897 * Function to take InterNet address and fill in IMP leader fields. 898 */ 899 imp_addr_to_leader(imp, a) 900 register struct control_leader *imp; 901 u_long a; 902 { 903 register u_long addr = ntohl(a); 904 905 imp->dl_network = 0; /* !! */ 906 907 if (IN_CLASSA(addr)) { 908 imp->dl_host = ((addr>>16) & 0xFF); 909 imp->dl_imp = addr & 0xFF; 910 } else if (IN_CLASSB(addr)) { 911 imp->dl_host = ((addr>>8) & 0xFF); 912 imp->dl_imp = addr & 0xFF; 913 } else { 914 imp->dl_host = ((addr>>4) & 0xF); 915 imp->dl_imp = addr & 0xF; 916 } 917 imp->dl_imp = htons(imp->dl_imp); 918 } 919 #endif 920