|
|
1.1 ! root 1: /* if_imp.c 6.1 83/07/29 */ ! 2: ! 3: #include "imp.h" ! 4: #if NIMP > 0 ! 5: /* ! 6: * ARPANET IMP interface driver. ! 7: * ! 8: * The IMP-host protocol is handled here, leaving ! 9: * hardware specifics to the lower level interface driver. ! 10: * ! 11: * NB: only handles IMPS on class A networks. ! 12: */ ! 13: #include "../machine/pte.h" ! 14: ! 15: #include "../h/param.h" ! 16: #include "../h/systm.h" ! 17: #include "../h/mbuf.h" ! 18: #include "../h/buf.h" ! 19: #include "../h/protosw.h" ! 20: #include "../h/socket.h" ! 21: #include "../h/vmmac.h" ! 22: #include "../h/time.h" ! 23: #include "../h/kernel.h" ! 24: #include "../h/errno.h" ! 25: #include "../h/ioctl.h" ! 26: ! 27: #include "../vax/cpu.h" ! 28: #include "../vax/mtpr.h" ! 29: #include "../vaxuba/ubareg.h" ! 30: #include "../vaxuba/ubavar.h" ! 31: ! 32: #include "../net/if.h" ! 33: #include "../net/route.h" ! 34: ! 35: #include "../net/netisr.h" ! 36: #include "../netinet/in.h" ! 37: #include "../netinet/in_systm.h" ! 38: #include "../netinet/ip.h" ! 39: #include "../netinet/ip_var.h" ! 40: /* define IMPLEADERS here to get leader printing code */ ! 41: #include "../netimp/if_imp.h" ! 42: #include "../netimp/if_imphost.h" ! 43: ! 44: /* ! 45: * IMP software status per interface. ! 46: * (partially shared with the hardware specific module) ! 47: * ! 48: * Each interface is referenced by a network interface structure, ! 49: * imp_if, which the routing code uses to locate the interface. ! 50: * This structure contains the output queue for the interface, its ! 51: * address, ... IMP specific structures used in connecting the ! 52: * IMP software modules to the hardware specific interface routines ! 53: * are stored here. The common structures are made visible to the ! 54: * interface driver by passing a pointer to the hardware routine ! 55: * at "attach" time. ! 56: * ! 57: * NOTE: imp_if and imp_cb are assumed adjacent in hardware code. ! 58: */ ! 59: struct imp_softc { ! 60: struct ifnet imp_if; /* network visible interface */ ! 61: struct impcb imp_cb; /* hooks to hardware module */ ! 62: u_char imp_state; /* current state of IMP */ ! 63: char imp_dropcnt; /* used during initialization */ ! 64: } imp_softc[NIMP]; ! 65: ! 66: /* ! 67: * Messages from IMP regarding why ! 68: * it's going down. ! 69: */ ! 70: static char *impmessage[] = { ! 71: "in 30 seconds", ! 72: "for hardware PM", ! 73: "to reload software", ! 74: "for emergency reset" ! 75: }; ! 76: ! 77: int impdown(), impinit(), impioctl(), impoutput(); ! 78: ! 79: /* ! 80: * IMP attach routine. Called from hardware device attach routine ! 81: * at configuration time with a pointer to the UNIBUS device structure. ! 82: * Sets up local state and returns pointer to base of ifnet+impcb ! 83: * structures. This is then used by the device's attach routine ! 84: * set up its back pointers. ! 85: */ ! 86: impattach(ui, reset) ! 87: struct uba_device *ui; ! 88: int (*reset)(); ! 89: { ! 90: struct imp_softc *sc = &imp_softc[ui->ui_unit]; ! 91: register struct ifnet *ifp = &sc->imp_if; ! 92: ! 93: /* UNIT COULD BE AMBIGUOUS */ ! 94: ifp->if_unit = ui->ui_unit; ! 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: /* reset is handled at the hardware level */ ! 102: if_attach(ifp); ! 103: return ((int)&sc->imp_if); ! 104: } ! 105: ! 106: /* ! 107: * IMP initialization routine: call hardware module to ! 108: * setup UNIBUS resources, init state and get ready for ! 109: * NOOPs the IMP should send us, and that we want to drop. ! 110: */ ! 111: impinit(unit) ! 112: int unit; ! 113: { ! 114: int s = splimp(); ! 115: register struct imp_softc *sc = &imp_softc[unit]; ! 116: struct sockaddr_in *sin; ! 117: ! 118: sin = (struct sockaddr_in *)&sc->imp_if.if_addr; ! 119: if (in_netof(sin->sin_addr) == 0) ! 120: return; ! 121: if ((*sc->imp_cb.ic_init)(unit) == 0) { ! 122: sc->imp_state = IMPS_DOWN; ! 123: sc->imp_if.if_flags &= ~IFF_UP; ! 124: splx(s); ! 125: return; ! 126: } ! 127: sc->imp_if.if_flags |= IFF_RUNNING; ! 128: sc->imp_state = IMPS_INIT; ! 129: impnoops(sc); ! 130: splx(s); ! 131: } ! 132: ! 133: struct sockproto impproto = { PF_IMPLINK }; ! 134: struct sockaddr_in impdst = { AF_IMPLINK }; ! 135: struct sockaddr_in impsrc = { AF_IMPLINK }; ! 136: #ifdef IMPLEADERS ! 137: int impprintfs = 0; ! 138: #endif ! 139: ! 140: /* ! 141: * ARPAnet 1822 input routine. ! 142: * Called from hardware input interrupt routine to handle 1822 ! 143: * IMP-host messages. Type 0 messages (non-control) are ! 144: * passed to higher level protocol processors on the basis ! 145: * of link number. Other type messages (control) are handled here. ! 146: */ ! 147: impinput(unit, m) ! 148: int unit; ! 149: register struct mbuf *m; ! 150: { ! 151: register struct imp_leader *ip; ! 152: register struct imp_softc *sc = &imp_softc[unit]; ! 153: register struct host *hp; ! 154: register struct ifqueue *inq; ! 155: struct control_leader *cp; ! 156: struct in_addr addr; ! 157: struct mbuf *next; ! 158: struct sockaddr_in *sin; ! 159: ! 160: /* verify leader length. */ ! 161: if (m->m_len < sizeof(struct control_leader) && ! 162: (m = m_pullup(m, sizeof(struct control_leader))) == 0) ! 163: return; ! 164: cp = mtod(m, struct control_leader *); ! 165: if (cp->dl_mtype == IMPTYPE_DATA) ! 166: if (m->m_len < sizeof(struct imp_leader) && ! 167: (m = m_pullup(m, sizeof(struct imp_leader))) == 0) ! 168: return; ! 169: ip = mtod(m, struct imp_leader *); ! 170: #ifdef IMPLEADERS ! 171: if (impprintfs) ! 172: printleader("impinput", ip); ! 173: #endif ! 174: ! 175: /* check leader type */ ! 176: if (ip->il_format != IMP_NFF) { ! 177: sc->imp_if.if_collisions++; /* XXX */ ! 178: goto drop; ! 179: } ! 180: ! 181: if (ip->il_mtype != IMPTYPE_DATA) { ! 182: #ifdef notdef ! 183: addr.s_net = ip->il_network; ! 184: #else ! 185: addr.s_net = sc->imp_if.if_net; ! 186: #endif ! 187: addr.s_imp = ip->il_imp; ! 188: addr.s_host = ip->il_host; ! 189: } ! 190: switch (ip->il_mtype) { ! 191: ! 192: case IMPTYPE_DATA: ! 193: break; ! 194: ! 195: /* ! 196: * IMP leader error. Reset the IMP and discard the packet. ! 197: */ ! 198: case IMPTYPE_BADLEADER: ! 199: /* ! 200: * According to 1822 document, this message ! 201: * will be generated in response to the ! 202: * first noop sent to the IMP after ! 203: * the host resets the IMP interface. ! 204: */ ! 205: if (sc->imp_state != IMPS_INIT) { ! 206: impmsg(sc, "leader error"); ! 207: hostreset(sc->imp_if.if_net); ! 208: impnoops(sc); ! 209: } ! 210: goto drop; ! 211: ! 212: /* ! 213: * IMP going down. Print message, and if not immediate, ! 214: * set off a timer to insure things will be reset at the ! 215: * appropriate time. ! 216: */ ! 217: case IMPTYPE_DOWN: ! 218: if (sc->imp_state < IMPS_INIT) ! 219: goto drop; ! 220: if ((ip->il_link & IMP_DMASK) == 0) { ! 221: sc->imp_state = IMPS_GOINGDOWN; ! 222: timeout(impdown, (caddr_t)sc, 30 * hz); ! 223: } ! 224: impmsg(sc, "going down %s", ! 225: (u_int)impmessage[ip->il_link&IMP_DMASK]); ! 226: goto drop; ! 227: ! 228: /* ! 229: * A NOP usually seen during the initialization sequence. ! 230: * Compare the local address with that in the message. ! 231: * Reset the local address notion if it doesn't match. ! 232: */ ! 233: case IMPTYPE_NOOP: ! 234: if (sc->imp_state == IMPS_DOWN) { ! 235: sc->imp_state = IMPS_INIT; ! 236: sc->imp_dropcnt = IMP_DROPCNT; ! 237: } ! 238: if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt > 0) ! 239: goto drop; ! 240: sin = (struct sockaddr_in *)&sc->imp_if.if_addr; ! 241: if (sin->sin_addr.s_host != ip->il_host || ! 242: sin->sin_addr.s_imp != ip->il_imp) { ! 243: sc->imp_if.if_host[0] = ! 244: sin->sin_addr.s_host = ip->il_host; ! 245: sin->sin_addr.s_imp = ip->il_imp; ! 246: impmsg(sc, "reset (host %d/imp %d)", (u_int)ip->il_host, ! 247: ntohs(ip->il_imp)); ! 248: } ! 249: sc->imp_state = IMPS_UP; ! 250: sc->imp_if.if_flags |= IFF_UP; ! 251: if_rtinit(&sc->imp_if, RTF_UP); ! 252: goto drop; ! 253: ! 254: /* ! 255: * RFNM or INCOMPLETE message, send next ! 256: * message on the q. We could pass incomplete's ! 257: * up to the next level, but this currently isn't ! 258: * needed. ! 259: */ ! 260: case IMPTYPE_RFNM: ! 261: case IMPTYPE_INCOMPLETE: ! 262: if (hp = hostlookup(addr)) { ! 263: if (hp->h_rfnm == 0) ! 264: hp->h_flags &= ~HF_INUSE; ! 265: else if (next = hostdeque(hp)) ! 266: (void) impsnd(&sc->imp_if, next); ! 267: } ! 268: goto drop; ! 269: ! 270: /* ! 271: * Host or IMP can't be reached. Flush any packets ! 272: * awaiting transmission and release the host structure. ! 273: */ ! 274: case IMPTYPE_HOSTDEAD: ! 275: case IMPTYPE_HOSTUNREACH: ! 276: impnotify((int)ip->il_mtype, (struct control_leader *)ip, ! 277: hostlookup(addr)); ! 278: goto rawlinkin; ! 279: ! 280: /* ! 281: * Error in data. Clear RFNM status for this host and send ! 282: * noops to the IMP to clear the interface. ! 283: */ ! 284: case IMPTYPE_BADDATA: ! 285: impmsg(sc, "data error"); ! 286: if (hp = hostlookup(addr)) ! 287: hp->h_rfnm = 0; ! 288: impnoops(sc); ! 289: goto drop; ! 290: ! 291: /* ! 292: * Interface reset. ! 293: */ ! 294: case IMPTYPE_RESET: ! 295: impmsg(sc, "interface reset"); ! 296: impnoops(sc); ! 297: goto drop; ! 298: ! 299: default: ! 300: sc->imp_if.if_collisions++; /* XXX */ ! 301: goto drop; ! 302: } ! 303: ! 304: /* ! 305: * Data for a protocol. Dispatch to the appropriate ! 306: * protocol routine (running at software interrupt). ! 307: * If this isn't a raw interface, advance pointer ! 308: * into mbuf past leader. ! 309: */ ! 310: switch (ip->il_link) { ! 311: ! 312: #ifdef INET ! 313: case IMPLINK_IP: ! 314: m->m_len -= sizeof(struct imp_leader); ! 315: m->m_off += sizeof(struct imp_leader); ! 316: schednetisr(NETISR_IP); ! 317: inq = &ipintrq; ! 318: break; ! 319: #endif ! 320: ! 321: default: ! 322: rawlinkin: ! 323: impproto.sp_protocol = ip->il_link; ! 324: sin = (struct sockaddr_in *)&sc->imp_if.if_addr; ! 325: impdst.sin_addr = sin->sin_addr;; ! 326: impsrc.sin_addr.s_net = ip->il_network; ! 327: impsrc.sin_addr.s_host = ip->il_host; ! 328: impsrc.sin_addr.s_imp = ip->il_imp; ! 329: raw_input(m, &impproto, (struct sockaddr *)&impsrc, ! 330: (struct sockaddr *)&impdst); ! 331: return; ! 332: } ! 333: if (IF_QFULL(inq)) { ! 334: IF_DROP(inq); ! 335: goto drop; ! 336: } ! 337: IF_ENQUEUE(inq, m); ! 338: return; ! 339: ! 340: drop: ! 341: m_freem(m); ! 342: } ! 343: ! 344: /* ! 345: * Bring the IMP down after notification. ! 346: */ ! 347: impdown(sc) ! 348: struct imp_softc *sc; ! 349: { ! 350: int s = splimp(); ! 351: ! 352: sc->imp_state = IMPS_DOWN; ! 353: impmsg(sc, "marked down"); ! 354: hostreset(sc->imp_if.if_net); ! 355: if_down(&sc->imp_if); ! 356: splx(s); ! 357: } ! 358: ! 359: /*VARARGS*/ ! 360: impmsg(sc, fmt, a1, a2) ! 361: struct imp_softc *sc; ! 362: char *fmt; ! 363: u_int a1; ! 364: { ! 365: ! 366: printf("imp%d: ", sc->imp_if.if_unit); ! 367: printf(fmt, a1, a2); ! 368: printf("\n"); ! 369: } ! 370: ! 371: /* ! 372: * Process an IMP "error" message, passing this ! 373: * up to the higher level protocol. ! 374: */ ! 375: impnotify(what, cp, hp) ! 376: int what; ! 377: struct control_leader *cp; ! 378: struct host *hp; ! 379: { ! 380: struct in_addr in; ! 381: ! 382: #ifdef notdef ! 383: in.s_net = cp->dl_network; ! 384: #else ! 385: in.s_net = 10; /* XXX */ ! 386: #endif ! 387: in.s_host = cp->dl_host; ! 388: in.s_imp = cp->dl_imp; ! 389: if (cp->dl_link != IMPLINK_IP) ! 390: raw_ctlinput(what, (caddr_t)&in); ! 391: else ! 392: ip_ctlinput(what, (caddr_t)&in); ! 393: if (hp) { ! 394: hp->h_flags |= (1 << what); ! 395: hostfree(hp); ! 396: } ! 397: } ! 398: ! 399: /* ! 400: * ARPAnet 1822 output routine. ! 401: * Called from higher level protocol routines to set up messages for ! 402: * transmission to the imp. Sets up the header and calls impsnd to ! 403: * enqueue the message for this IMP's hardware driver. ! 404: */ ! 405: impoutput(ifp, m0, dst) ! 406: register struct ifnet *ifp; ! 407: struct mbuf *m0; ! 408: struct sockaddr *dst; ! 409: { ! 410: register struct imp_leader *imp; ! 411: register struct mbuf *m = m0; ! 412: int dhost, dimp, dlink, len, dnet; ! 413: int error = 0; ! 414: ! 415: /* ! 416: * Don't even try if the IMP is unavailable. ! 417: */ ! 418: if (imp_softc[ifp->if_unit].imp_state != IMPS_UP) { ! 419: error = ENETDOWN; ! 420: goto drop; ! 421: } ! 422: ! 423: switch (dst->sa_family) { ! 424: ! 425: #ifdef INET ! 426: case AF_INET: { ! 427: struct ip *ip = mtod(m0, struct ip *); ! 428: struct sockaddr_in *sin = (struct sockaddr_in *)dst; ! 429: ! 430: dhost = sin->sin_addr.s_host; ! 431: dimp = sin->sin_addr.s_impno; ! 432: dlink = IMPLINK_IP; ! 433: dnet = 0; ! 434: len = ntohs((u_short)ip->ip_len); ! 435: break; ! 436: } ! 437: #endif ! 438: case AF_IMPLINK: ! 439: goto leaderexists; ! 440: ! 441: default: ! 442: printf("imp%d: can't handle af%d\n", ifp->if_unit, ! 443: dst->sa_family); ! 444: error = EAFNOSUPPORT; ! 445: goto drop; ! 446: } ! 447: ! 448: /* ! 449: * Add IMP leader. If there's not enough space in the ! 450: * first mbuf, allocate another. If that should fail, we ! 451: * drop this sucker. ! 452: */ ! 453: if (m->m_off > MMAXOFF || ! 454: MMINOFF + sizeof(struct imp_leader) > m->m_off) { ! 455: m = m_get(M_DONTWAIT, MT_HEADER); ! 456: if (m == 0) { ! 457: error = ENOBUFS; ! 458: goto drop; ! 459: } ! 460: m->m_next = m0; ! 461: m->m_len = sizeof(struct imp_leader); ! 462: } else { ! 463: m->m_off -= sizeof(struct imp_leader); ! 464: m->m_len += sizeof(struct imp_leader); ! 465: } ! 466: imp = mtod(m, struct imp_leader *); ! 467: imp->il_format = IMP_NFF; ! 468: imp->il_mtype = IMPTYPE_DATA; ! 469: imp->il_network = dnet; ! 470: imp->il_host = dhost; ! 471: imp->il_imp = htons((u_short)dimp); ! 472: imp->il_length = ! 473: htons((u_short)(len + sizeof(struct imp_leader)) << 3); ! 474: imp->il_link = dlink; ! 475: imp->il_flags = imp->il_htype = imp->il_subtype = 0; ! 476: ! 477: leaderexists: ! 478: return (impsnd(ifp, m)); ! 479: drop: ! 480: m_freem(m0); ! 481: return (error); ! 482: } ! 483: ! 484: /* ! 485: * Put a message on an interface's output queue. ! 486: * Perform RFNM counting: no more than 8 message may be ! 487: * in flight to any one host. ! 488: */ ! 489: impsnd(ifp, m) ! 490: struct ifnet *ifp; ! 491: struct mbuf *m; ! 492: { ! 493: register struct imp_leader *ip; ! 494: register struct host *hp; ! 495: struct impcb *icp; ! 496: int s, error; ! 497: ! 498: ip = mtod(m, struct imp_leader *); ! 499: ! 500: /* ! 501: * Do RFNM counting for data messages ! 502: * (no more than 8 outstanding to any host) ! 503: */ ! 504: s = splimp(); ! 505: if (ip->il_mtype == IMPTYPE_DATA) { ! 506: struct in_addr addr; ! 507: ! 508: #ifdef notdef ! 509: addr.s_net = ip->il_network; ! 510: #else ! 511: addr.s_net = ifp->if_net; /* XXX */ ! 512: #endif ! 513: addr.s_host = ip->il_host; ! 514: addr.s_imp = ip->il_imp; ! 515: if ((hp = hostlookup(addr)) == 0) ! 516: hp = hostenter(addr); ! 517: if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) { ! 518: error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH; ! 519: hp->h_timer = HOSTTIMER; ! 520: hp->h_flags &= ~HF_INUSE; ! 521: goto bad; ! 522: } ! 523: ! 524: /* ! 525: * If IMP would block, queue until RFNM ! 526: */ ! 527: if (hp) { ! 528: if (hp->h_rfnm < 8) { ! 529: hp->h_rfnm++; ! 530: goto enque; ! 531: } ! 532: if (hp->h_qcnt < 8) { /* high water mark */ ! 533: HOST_ENQUE(hp, m); ! 534: goto start; ! 535: } ! 536: } ! 537: error = ENOBUFS; ! 538: goto bad; ! 539: } ! 540: enque: ! 541: if (IF_QFULL(&ifp->if_snd)) { ! 542: IF_DROP(&ifp->if_snd); ! 543: error = ENOBUFS; ! 544: bad: ! 545: m_freem(m); ! 546: splx(s); ! 547: return (error); ! 548: } ! 549: IF_ENQUEUE(&ifp->if_snd, m); ! 550: start: ! 551: icp = &imp_softc[ifp->if_unit].imp_cb; ! 552: if (icp->ic_oactive == 0) ! 553: (*icp->ic_start)(ifp->if_unit); ! 554: splx(s); ! 555: return (0); ! 556: } ! 557: ! 558: /* ! 559: * Put three 1822 NOOPs at the head of the output queue. ! 560: * Part of host-IMP initialization procedure. ! 561: * (Should return success/failure, but noone knows ! 562: * what to do with this, so why bother?) ! 563: * This routine is always called at splimp, so we don't ! 564: * protect the call to IF_PREPEND. ! 565: */ ! 566: impnoops(sc) ! 567: register struct imp_softc *sc; ! 568: { ! 569: register i; ! 570: register struct mbuf *m; ! 571: register struct control_leader *cp; ! 572: ! 573: sc->imp_dropcnt = IMP_DROPCNT; ! 574: for (i = 0; i < IMP_DROPCNT + 1; i++ ) { ! 575: if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0) ! 576: return; ! 577: m->m_len = sizeof(struct control_leader); ! 578: cp = mtod(m, struct control_leader *); ! 579: cp->dl_format = IMP_NFF; ! 580: cp->dl_link = i; ! 581: cp->dl_mtype = IMPTYPE_NOOP; ! 582: IF_PREPEND(&sc->imp_if.if_snd, m); ! 583: } ! 584: if (sc->imp_cb.ic_oactive == 0) ! 585: (*sc->imp_cb.ic_start)(sc->imp_if.if_unit); ! 586: } ! 587: ! 588: /* ! 589: * Process an ioctl request. ! 590: */ ! 591: impioctl(ifp, cmd, data) ! 592: register struct ifnet *ifp; ! 593: int cmd; ! 594: caddr_t data; ! 595: { ! 596: struct ifreq *ifr = (struct ifreq *)data; ! 597: struct sockaddr_in *sin; ! 598: int s = splimp(), error = 0; ! 599: ! 600: switch (cmd) { ! 601: ! 602: case SIOCSIFADDR: ! 603: if (ifp->if_flags & IFF_RUNNING) ! 604: if_rtinit(ifp, -1); /* delete previous route */ ! 605: sin = (struct sockaddr_in *)&ifr->ifr_addr; ! 606: ifp->if_net = in_netof(sin->sin_addr); ! 607: sin = (struct sockaddr_in *)&ifp->if_addr; ! 608: sin->sin_family = AF_INET; ! 609: /* host number filled in already, or filled in later */ ! 610: sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); ! 611: if (ifp->if_flags & IFF_RUNNING) ! 612: if_rtinit(ifp, RTF_UP); ! 613: else ! 614: impinit(ifp->if_unit); ! 615: break; ! 616: ! 617: default: ! 618: error = EINVAL; ! 619: } ! 620: splx(s); ! 621: return (error); ! 622: } ! 623: ! 624: #ifdef IMPLEADERS ! 625: printleader(routine, ip) ! 626: char *routine; ! 627: register struct imp_leader *ip; ! 628: { ! 629: printf("%s: ", routine); ! 630: printbyte((char *)ip, 12); ! 631: printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network, ! 632: ip->il_flags); ! 633: if (ip->il_mtype <= IMPTYPE_READY) ! 634: printf("%s,", impleaders[ip->il_mtype]); ! 635: else ! 636: printf("%x,", ip->il_mtype); ! 637: printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host, ! 638: ntohs(ip->il_imp)); ! 639: if (ip->il_link == IMPLINK_IP) ! 640: printf("ip,"); ! 641: else ! 642: printf("%x,", ip->il_link); ! 643: printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3); ! 644: } ! 645: ! 646: printbyte(cp, n) ! 647: register char *cp; ! 648: int n; ! 649: { ! 650: register i, j, c; ! 651: ! 652: for (i=0; i<n; i++) { ! 653: c = *cp++; ! 654: for (j=0; j<2; j++) ! 655: putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]); ! 656: putchar(' '); ! 657: } ! 658: putchar('\n'); ! 659: } ! 660: #endif ! 661: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.