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_imp.c 1.2 (2.11BSD Berkeley) 12/31/93 7: */ 8: 9: #include "imp.h" 10: #if NIMP > 0 11: /* 12: * ARPANET IMP interface driver. 13: * 14: * The IMP-host protocol is handled here, leaving 15: * hardware specifics to the lower level interface driver. 16: */ 17: #include "param.h" 18: #include "systm.h" 19: #include "mbuf.h" 20: #include "buf.h" 21: #include "domain.h" 22: #include "protosw.h" 23: #include "socket.h" 24: #include "pdpuba/ubavar.h" 25: #include "ioctl.h" 26: #include <net/if.h> 27: #include <net/netisr.h> 28: #include <net/route.h> 29: #include <netinet/in.h> 30: #include <netinet/in_systm.h> 31: #include <netinet/in_var.h> 32: #include <netinet/ip.h> 33: #include <netinet/ip_var.h> 34: /* define IMPLEADERS here to get leader printing code */ 35: #include <netimp/if_imp.h> 36: #include <netimp/if_imphost.h> 37: #include <errno.h> 38: 39: #ifdef pdp11 40: #define putchar _pchar 41: #endif 42: 43: /* 44: * IMP software status per interface. 45: * (partially shared with the hardware specific module) 46: * 47: * Each interface is referenced by a network interface structure, 48: * imp_if, which the routing code uses to locate the interface. 49: * This structure contains the output queue for the interface, its 50: * address, ... IMP specific structures used in connecting the 51: * IMP software modules to the hardware specific interface routines 52: * are stored here. The common structures are made visible to the 53: * interface driver by passing a pointer to the hardware routine 54: * at "attach" time. 55: * 56: * NOTE: imp_if and imp_cb are assumed adjacent in hardware code. 57: */ 58: struct imp_softc { 59: struct ifnet imp_if; /* network visible interface */ 60: struct impcb imp_cb; /* hooks to hardware module */ 61: u_char imp_state; /* current state of IMP */ 62: char imp_dropcnt; /* used during initialization */ 63: } imp_softc[NIMP]; 64: 65: extern int hz; 66: struct ifqueue impintrq; 67: int impqmaxlen = IFQ_MAXLEN; 68: 69: /* 70: * Messages from IMP regarding why 71: * it's going down. 72: */ 73: static char *impmessage[] = { 74: "in 30 seconds", 75: "for hardware PM", 76: "to reload software", 77: "for emergency reset" 78: }; 79: 80: #define HOSTDEADTIMER 10 /* How long to wait when down */ 81: 82: int impdown(), impinit(), impioctl(), impoutput(); 83: 84: /* 85: * IMP attach routine. Called from hardware device attach routine 86: * at configuration time with a pointer to the UNIBUS device structure. 87: * Sets up local state and returns pointer to base of ifnet+impcb 88: * structures. This is then used by the device's attach routine 89: * set up its back pointers. 90: */ 91: impattach(ui, reset) 92: struct uba_device *ui; 93: int (*reset)(); 94: { 95: struct imp_softc *sc; 96: register struct ifnet *ifp; 97: 98: #ifdef lint 99: impintr(); 100: #endif 101: if (ui->ui_unit >= NIMP) { 102: printf("imp%d: not configured\n", ui->ui_unit); 103: return (0); 104: } 105: sc = &imp_softc[ui->ui_unit]; 106: ifp = &sc->imp_if; 107: /* UNIT COULD BE AMBIGUOUS */ 108: ifp->if_unit = ui->ui_unit; 109: ifp->if_name = "imp"; 110: ifp->if_mtu = IMPMTU - sizeof(struct imp_leader); 111: ifp->if_reset = reset; 112: ifp->if_init = impinit; 113: ifp->if_ioctl = impioctl; 114: ifp->if_output = impoutput; 115: /* reset is handled at the hardware level */ 116: if_attach(ifp); 117: return ((int)ifp); 118: } 119: 120: /* 121: * IMP initialization routine: call hardware module to 122: * setup UNIBUS resources, init state and get ready for 123: * NOOPs the IMP should send us, and that we want to drop. 124: */ 125: impinit(unit) 126: int unit; 127: { 128: int s = splimp(); 129: register struct imp_softc *sc = &imp_softc[unit]; 130: 131: if (sc->imp_if.if_addrlist == 0) 132: return; 133: if ((*sc->imp_cb.ic_init)(unit) == 0) { 134: sc->imp_state = IMPS_DOWN; 135: sc->imp_if.if_flags &= ~IFF_UP; 136: splx(s); 137: return; 138: } 139: sc->imp_state = IMPS_INIT; 140: impnoops(sc); 141: impintrq.ifq_maxlen = impqmaxlen; 142: splx(s); 143: } 144: 145: #ifdef IMPLEADERS 146: int impprintfs = 0; 147: #endif 148: 149: /* 150: * ARPAnet 1822 input routine. 151: * Called from hardware input interrupt routine to handle 1822 152: * IMP-host messages. Type 0 messages (non-control) are 153: * passed to higher level protocol processors on the basis 154: * of link number. Other type messages (control) are handled here. 155: */ 156: impinput(unit, m) 157: int unit; 158: register struct mbuf *m; 159: { 160: register struct imp_leader *ip; 161: register struct imp_softc *sc = &imp_softc[unit]; 162: struct ifnet *ifp; 163: register struct host *hp; 164: register struct ifqueue *inq; 165: struct control_leader *cp; 166: struct in_addr addr; 167: struct mbuf *next; 168: struct sockaddr_in *sin; 169: 170: /* 171: * Pull the interface pointer out of the mbuf 172: * and save for later; adjust mbuf to look at rest of data. 173: */ 174: ifp = *(mtod(m, struct ifnet **)); 175: IF_ADJ(m); 176: /* verify leader length. */ 177: if (m->m_len < sizeof(struct control_leader) && 178: (m = m_pullup(m, sizeof(struct control_leader))) == 0) 179: return; 180: cp = mtod(m, struct control_leader *); 181: if (cp->dl_mtype == IMPTYPE_DATA) 182: if (m->m_len < sizeof(struct imp_leader) && 183: (m = m_pullup(m, sizeof(struct imp_leader))) == 0) 184: return; 185: ip = mtod(m, struct imp_leader *); 186: #ifdef IMPLEADERS 187: if (impprintfs) 188: printleader("impinput", ip); 189: #endif 190: inq = &impintrq; 191: 192: /* check leader type */ 193: if (ip->il_format != IMP_NFF) { 194: sc->imp_if.if_collisions++; /* XXX */ 195: goto rawlinkin; 196: } 197: 198: if (ip->il_mtype != IMPTYPE_DATA) { 199: /* If not data packet, build IP addr from leader (BRL) */ 200: imp_leader_to_addr(&addr, ip, &sc->imp_if); 201: } 202: 203: switch (ip->il_mtype) { 204: 205: case IMPTYPE_DATA: 206: /* 207: * Data for a protocol. Dispatch to the appropriate 208: * protocol routine (running at software interrupt). 209: * If this isn't a raw interface, advance pointer 210: * into mbuf past leader. 211: */ 212: switch (ip->il_link) { 213: 214: case IMPLINK_IP: 215: m->m_len -= sizeof(struct imp_leader); 216: m->m_off += sizeof(struct imp_leader); 217: schednetisr(NETISR_IP); 218: inq = &ipintrq; 219: break; 220: 221: default: 222: break; 223: } 224: break; 225: 226: /* 227: * IMP leader error. Reset the IMP and discard the packet. 228: */ 229: case IMPTYPE_BADLEADER: 230: /* 231: * According to 1822 document, this message 232: * will be generated in response to the 233: * first noop sent to the IMP after 234: * the host resets the IMP interface. 235: */ 236: if (sc->imp_state != IMPS_INIT) { 237: impmsg(sc, "leader error"); 238: hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net); 239: impnoops(sc); 240: } 241: break; 242: 243: /* 244: * IMP going down. Print message, and if not immediate, 245: * set off a timer to insure things will be reset at the 246: * appropriate time. 247: */ 248: case IMPTYPE_DOWN: 249: if (sc->imp_state < IMPS_INIT) 250: break; 251: if ((ip->il_link & IMP_DMASK) == 0) { 252: sc->imp_state = IMPS_GOINGDOWN; 253: TIMEOUT(impdown, (caddr_t)sc, 30 * hz); 254: } 255: impmsg(sc, "going down %s", 256: (u_int)impmessage[ip->il_link&IMP_DMASK]); 257: break; 258: 259: /* 260: * A NOP usually seen during the initialization sequence. 261: * Compare the local address with that in the message. 262: * Reset the local address notion if it doesn't match. 263: */ 264: case IMPTYPE_NOOP: 265: if (sc->imp_state == IMPS_DOWN) { 266: sc->imp_state = IMPS_INIT; 267: sc->imp_dropcnt = IMP_DROPCNT; 268: } 269: if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt > 0) 270: break; 271: sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr; 272: if (ip->il_imp != 0) { 273: struct in_addr leader_addr; 274: 275: imp_leader_to_addr(&leader_addr, ip, &sc->imp_if); 276: if (sin->sin_addr.s_addr != leader_addr.s_addr) { 277: impmsg(sc, "address reset to x%x (%d/%d)", 278: ntohl(leader_addr.s_addr), 279: (u_int)ip->il_host, 280: ntohs(ip->il_imp)); 281: sin->sin_addr.s_addr = leader_addr.s_addr; 282: } 283: } 284: sc->imp_state = IMPS_UP; 285: sc->imp_if.if_flags |= IFF_UP; 286: break; 287: 288: /* 289: * RFNM or INCOMPLETE message, send next 290: * message on the q. We could pass incomplete's 291: * up to the next level, but this currently isn't 292: * needed. 293: */ 294: case IMPTYPE_RFNM: 295: case IMPTYPE_INCOMPLETE: 296: if (hp = hostlookup(addr)) { 297: hp->h_timer = HOSTTIMER; 298: if (hp->h_rfnm == 0) 299: hp->h_flags &= ~HF_INUSE; 300: else if (next = hostdeque(hp)) 301: (void) impsnd(&sc->imp_if, next); 302: } 303: goto drop; 304: 305: /* 306: * Host or IMP can't be reached. Flush any packets 307: * awaiting transmission and release the host structure. 308: * Enqueue for notifying protocols at software interrupt time. 309: */ 310: case IMPTYPE_HOSTDEAD: 311: case IMPTYPE_HOSTUNREACH: 312: if (hp = hostlookup(addr)) { 313: hp->h_flags |= (1 << (int)ip->il_mtype); 314: hostfree(hp); 315: hp->h_timer = HOSTDEADTIMER; 316: } 317: break; 318: 319: /* 320: * Error in data. Clear RFNM status for this host and send 321: * noops to the IMP to clear the interface. 322: */ 323: case IMPTYPE_BADDATA: 324: impmsg(sc, "data error"); 325: if (hp = hostlookup(addr)) 326: hp->h_rfnm = 0; 327: impnoops(sc); 328: break; 329: 330: /* 331: * Interface reset. 332: */ 333: case IMPTYPE_RESET: 334: impmsg(sc, "interface reset"); 335: /* clear RFNM counts */ 336: hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net); 337: impnoops(sc); 338: break; 339: 340: default: 341: sc->imp_if.if_collisions++; /* XXX */ 342: break; 343: } 344: 345: rawlinkin: 346: if (inq == &impintrq) 347: schednetisr(NETISR_IMP); 348: /* 349: * Re-insert interface pointer in the mbuf chain 350: * for the next protocol up. 351: */ 352: if (M_HASCL(m) && (mtod(m, int) & CLOFSET) < sizeof(struct ifnet *)) { 353: struct mbuf *n; 354: 355: MGET(n, M_DONTWAIT, MT_HEADER); 356: if (n == 0) 357: goto drop; 358: n->m_next = m; 359: m = n; 360: m->m_len = 0; 361: m->m_off = MMINOFF + sizeof(struct ifnet *); 362: } 363: m->m_off -= sizeof(struct ifnet *); 364: m->m_len += sizeof(struct ifnet *); 365: *(mtod(m, struct ifnet **)) = ifp; 366: 367: if (IF_QFULL(inq)) { 368: IF_DROP(inq); 369: goto drop; 370: } 371: IF_ENQUEUE(inq, m); 372: return; 373: 374: drop: 375: m_freem(m); 376: } 377: 378: /* 379: * Bring the IMP down after notification. 380: */ 381: impdown(sc) 382: struct imp_softc *sc; 383: { 384: int s = splimp(); 385: 386: sc->imp_state = IMPS_DOWN; 387: impmsg(sc, "marked down"); 388: hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net); 389: if_down(&sc->imp_if); 390: splx(s); 391: } 392: 393: /*VARARGS2*/ 394: impmsg(sc, fmt, a1, a2, a3) 395: struct imp_softc *sc; 396: char *fmt; 397: u_int a1; 398: { 399: 400: printf("imp%d: ", sc->imp_if.if_unit); 401: printf(fmt, a1, a2, a3); 402: printf("\n"); 403: } 404: 405: struct sockproto impproto = { PF_IMPLINK }; 406: struct sockaddr_in impdst = { AF_IMPLINK }; 407: struct sockaddr_in impsrc = { AF_IMPLINK }; 408: 409: /* 410: * Pick up the IMP "error" messages enqueued earlier, 411: * passing these up to the higher level protocol 412: * and the raw interface. 413: */ 414: impintr() 415: { 416: register struct mbuf *m; 417: register struct control_leader *cp; 418: struct ifnet *ifp; 419: int s; 420: 421: for (;;) { 422: s = splimp(); 423: IF_DEQUEUEIF(&impintrq, m, ifp); 424: splx(s); 425: if (m == 0) 426: return; 427: 428: cp = mtod(m, struct control_leader *); 429: imp_leader_to_addr(&impsrc.sin_addr, (struct imp_leader *)cp, 430: ifp); 431: impproto.sp_protocol = cp->dl_link; 432: impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr; 433: 434: if (cp->dl_mtype == IMPTYPE_HOSTDEAD || 435: cp->dl_mtype == IMPTYPE_HOSTUNREACH) 436: switch (cp->dl_link) { 437: 438: case IMPLINK_IP: 439: pfctlinput((int)cp->dl_mtype, 440: (struct sockaddr *)&impsrc); 441: break; 442: default: 443: raw_ctlinput((int)cp->dl_mtype, 444: (struct sockaddr *)&impsrc); 445: break; 446: } 447: 448: raw_input(m, &impproto, (struct sockaddr *)&impsrc, 449: (struct sockaddr *)&impdst); 450: } 451: } 452: 453: /* 454: * ARPAnet 1822 output routine. 455: * Called from higher level protocol routines to set up messages for 456: * transmission to the imp. Sets up the header and calls impsnd to 457: * enqueue the message for this IMP's hardware driver. 458: */ 459: impoutput(ifp, m0, dst) 460: register struct ifnet *ifp; 461: struct mbuf *m0; 462: struct sockaddr *dst; 463: { 464: register struct imp_leader *imp; 465: register struct mbuf *m = m0; 466: int dlink, len; 467: int error = 0; 468: 469: /* 470: * Don't even try if the IMP is unavailable. 471: */ 472: if (imp_softc[ifp->if_unit].imp_state != IMPS_UP) { 473: error = ENETDOWN; 474: goto drop; 475: } 476: 477: switch (dst->sa_family) { 478: 479: case AF_INET: { 480: struct ip *ip = mtod(m, struct ip *); 481: 482: dlink = IMPLINK_IP; 483: len = ntohs((u_short)ip->ip_len); 484: break; 485: } 486: 487: case AF_IMPLINK: 488: len = 0; 489: do 490: len += m->m_len; 491: while (m = m->m_next); 492: m = m0; 493: goto leaderexists; 494: 495: default: 496: printf("imp%d: can't handle af%d\n", ifp->if_unit, 497: dst->sa_family); 498: error = EAFNOSUPPORT; 499: goto drop; 500: } 501: 502: /* 503: * Add IMP leader. If there's not enough space in the 504: * first mbuf, allocate another. If that should fail, we 505: * drop this sucker. 506: */ 507: if (m->m_off > MMAXOFF || 508: MMINOFF + sizeof(struct imp_leader) > m->m_off) { 509: m = m_get(M_DONTWAIT, MT_HEADER); 510: if (m == 0) { 511: error = ENOBUFS; 512: goto drop; 513: } 514: m->m_next = m0; 515: m->m_len = sizeof(struct imp_leader); 516: } else { 517: m->m_off -= sizeof(struct imp_leader); 518: m->m_len += sizeof(struct imp_leader); 519: } 520: imp = mtod(m, struct imp_leader *); 521: imp->il_format = IMP_NFF; 522: imp->il_mtype = IMPTYPE_DATA; 523: imp_addr_to_leader(imp, 524: ((struct sockaddr_in *)dst)->sin_addr.s_addr); /* BRL */ 525: imp->il_length = htons((u_short)len << 3); /* BRL */ 526: imp->il_link = dlink; 527: imp->il_flags = imp->il_htype = imp->il_subtype = 0; 528: 529: leaderexists: 530: return (impsnd(ifp, m)); 531: drop: 532: m_freem(m0); 533: return (error); 534: } 535: 536: /* 537: * Put a message on an interface's output queue. 538: * Perform RFNM counting: no more than 8 message may be 539: * in flight to any one host. 540: */ 541: impsnd(ifp, m) 542: struct ifnet *ifp; 543: struct mbuf *m; 544: { 545: register struct imp_leader *ip; 546: register struct host *hp; 547: struct impcb *icp; 548: int s, error; 549: 550: ip = mtod(m, struct imp_leader *); 551: 552: /* 553: * Do RFNM counting for data messages 554: * (no more than 8 outstanding to any host) 555: */ 556: s = splimp(); 557: if (ip->il_mtype == IMPTYPE_DATA) { 558: struct in_addr addr; 559: 560: imp_leader_to_addr(&addr, ip, ifp); /* BRL */ 561: if ((hp = hostlookup(addr)) == 0) 562: hp = hostenter(addr); 563: if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) { 564: error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH; 565: hp->h_flags &= ~HF_INUSE; 566: goto bad; 567: } 568: 569: /* 570: * If IMP would block, queue until RFNM 571: */ 572: if (hp) { 573: #ifndef NORFNM 574: if (hp->h_rfnm < 8) 575: #endif 576: { 577: hp->h_timer = HOSTTIMER; 578: hp->h_rfnm++; 579: goto enque; 580: } 581: if (hp->h_qcnt < 8) { /* high water mark */ 582: HOST_ENQUE(hp, m); 583: goto start; 584: } 585: } 586: error = ENOBUFS; 587: goto bad; 588: } 589: enque: 590: if (IF_QFULL(&ifp->if_snd)) { 591: IF_DROP(&ifp->if_snd); 592: error = ENOBUFS; 593: if (ip->il_mtype == IMPTYPE_DATA) 594: hp->h_rfnm--; 595: bad: 596: m_freem(m); 597: splx(s); 598: return (error); 599: } 600: IF_ENQUEUE(&ifp->if_snd, m); 601: start: 602: icp = &imp_softc[ifp->if_unit].imp_cb; 603: if (icp->ic_oactive == 0) 604: (*icp->ic_start)(ifp->if_unit); 605: splx(s); 606: return (0); 607: } 608: 609: /* 610: * Put three 1822 NOOPs at the head of the output queue. 611: * Part of host-IMP initialization procedure. 612: * (Should return success/failure, but noone knows 613: * what to do with this, so why bother?) 614: * This routine is always called at splimp, so we don't 615: * protect the call to IF_PREPEND. 616: */ 617: impnoops(sc) 618: register struct imp_softc *sc; 619: { 620: register i; 621: register struct mbuf *m; 622: register struct control_leader *cp; 623: 624: sc->imp_dropcnt = IMP_DROPCNT; 625: for (i = 0; i < IMP_DROPCNT + 1; i++) { 626: if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0) 627: return; 628: m->m_len = sizeof(struct control_leader); 629: cp = mtod(m, struct control_leader *); 630: cp->dl_format = IMP_NFF; 631: cp->dl_link = i; 632: cp->dl_mtype = IMPTYPE_NOOP; 633: IF_PREPEND(&sc->imp_if.if_snd, m); 634: } 635: if (sc->imp_cb.ic_oactive == 0) 636: (*sc->imp_cb.ic_start)(sc->imp_if.if_unit); 637: } 638: 639: /* 640: * Process an ioctl request. 641: */ 642: impioctl(ifp, cmd, data) 643: register struct ifnet *ifp; 644: int cmd; 645: caddr_t data; 646: { 647: struct ifaddr *ifa = (struct ifaddr *) data; 648: int s = splimp(), error = 0; 649: 650: switch (cmd) { 651: 652: case SIOCSIFADDR: 653: if (ifa->ifa_addr.sa_family != AF_INET) { 654: error = EINVAL; 655: break; 656: } 657: if ((ifp->if_flags & IFF_RUNNING) == 0) 658: impinit(ifp->if_unit); 659: break; 660: 661: default: 662: error = EINVAL; 663: } 664: splx(s); 665: return (error); 666: } 667: 668: #ifdef IMPLEADERS 669: printleader(routine, ip) 670: char *routine; 671: register struct imp_leader *ip; 672: { 673: printf("%s: ", routine); 674: printbyte((char *)ip, 12); 675: printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network, 676: ip->il_flags); 677: if (UCHAR(ip->il_mtype) <= IMPTYPE_READY) 678: printf("%s,", impleaders[ip->il_mtype]); 679: else 680: printf("%x,", ip->il_mtype); 681: printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host, 682: ntohs(ip->il_imp)); 683: if (UCHAR(ip->il_link) == IMPLINK_IP) 684: printf("ip,"); 685: else 686: printf("%x,", ip->il_link); 687: printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3); 688: } 689: 690: printbyte(cp, n) 691: register char *cp; 692: int n; 693: { 694: register i, j, c; 695: 696: for (i=0; i<n; i++) { 697: c = *cp++; 698: for (j=0; j<2; j++) 699: putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0); 700: putchar(' ', 0); 701: } 702: putchar('\n', 0); 703: } 704: #endif 705: 706: /* 707: * Routine to convert from IMP Leader to InterNet Address. 708: * 709: * This procedure is necessary because IMPs may be assigned Class A, B, or C 710: * network numbers, but only have 8 bits in the leader to reflect the 711: * IMP "network number". The strategy is to take the network number from 712: * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers 713: * from the leader. 714: * 715: * There is no support for "Logical Hosts". 716: * 717: * Class A: Net.Host.0.Imp 718: * Class B: Net.net.Host.Imp 719: * Class C: Net.net.net.(Host4|Imp4) 720: */ 721: imp_leader_to_addr(ap, ip, ifp) 722: struct in_addr *ap; 723: register struct imp_leader *ip; 724: struct ifnet *ifp; 725: { 726: u_long final; 727: register struct sockaddr_in *sin; 728: int imp = ntohs(ip->il_imp); 729: 730: sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr); 731: final = ntohl(sin->sin_addr.s_addr); 732: 733: if (IN_CLASSA(final)) { 734: final &= IN_CLASSA_NET; 735: final |= (imp & 0xFF) | ((ip->il_host & 0xFF)<<16); 736: } else if (IN_CLASSB(final)) { 737: final &= IN_CLASSB_NET; 738: final |= (imp & 0xFF) | ((ip->il_host & 0xFF)<<8); 739: } else { 740: final &= IN_CLASSC_NET; 741: final |= (imp & 0x0F) | ((ip->il_host & 0x0F)<<4); 742: } 743: ap->s_addr = htonl(final); 744: } 745: 746: /* 747: * Function to take InterNet address and fill in IMP leader fields. 748: */ 749: imp_addr_to_leader(imp, a) 750: register struct imp_leader *imp; 751: u_long a; 752: { 753: u_long addr = ntohl(a); 754: 755: imp->il_network = 0; /* !! */ 756: 757: if (IN_CLASSA(addr)) { 758: imp->il_host = ((addr>>16) & 0xFF); 759: imp->il_imp = addr & 0xFF; 760: } else if (IN_CLASSB(addr)) { 761: imp->il_host = ((addr>>8) & 0xFF); 762: imp->il_imp = addr & 0xFF; 763: } else { 764: imp->il_host = ((addr>>4) & 0xF); 765: imp->il_imp = addr & 0xF; 766: } 767: imp->il_imp = htons(imp->il_imp); 768: } 769: #endif