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