1 |
|
|
/* $OpenBSD: print-decnet.c,v 1.17 2015/11/16 00:16:39 mmcc Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997 |
5 |
|
|
* The Regents of the University of California. All rights reserved. |
6 |
|
|
* |
7 |
|
|
* Redistribution and use in source and binary forms, with or without |
8 |
|
|
* modification, are permitted provided that: (1) source code distributions |
9 |
|
|
* retain the above copyright notice and this paragraph in its entirety, (2) |
10 |
|
|
* distributions including binary code include the above copyright notice and |
11 |
|
|
* this paragraph in its entirety in the documentation or other materials |
12 |
|
|
* provided with the distribution, and (3) all advertising materials mentioning |
13 |
|
|
* features or use of this software display the following acknowledgement: |
14 |
|
|
* ``This product includes software developed by the University of California, |
15 |
|
|
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
16 |
|
|
* the University nor the names of its contributors may be used to endorse |
17 |
|
|
* or promote products derived from this software without specific prior |
18 |
|
|
* written permission. |
19 |
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
20 |
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
21 |
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
#include <sys/time.h> |
25 |
|
|
#include <sys/socket.h> |
26 |
|
|
|
27 |
|
|
struct mbuf; |
28 |
|
|
struct rtentry; |
29 |
|
|
#include <net/if.h> |
30 |
|
|
|
31 |
|
|
#ifdef HAVE_LIBDNET |
32 |
|
|
#include <netdnet/dnetdb.h> |
33 |
|
|
#endif |
34 |
|
|
|
35 |
|
|
#include <ctype.h> |
36 |
|
|
#include <stdio.h> |
37 |
|
|
#include <stdlib.h> |
38 |
|
|
#include <string.h> |
39 |
|
|
#include <unistd.h> |
40 |
|
|
|
41 |
|
|
#include "decnet.h" |
42 |
|
|
#include "extract.h" |
43 |
|
|
#include "interface.h" |
44 |
|
|
#include "addrtoname.h" |
45 |
|
|
|
46 |
|
|
/* Forwards */ |
47 |
|
|
static int print_decnet_ctlmsg(const union routehdr *, u_int, u_int); |
48 |
|
|
static void print_t_info(int); |
49 |
|
|
static int print_l1_routes(const char *, u_int); |
50 |
|
|
static int print_l2_routes(const char *, u_int); |
51 |
|
|
static void print_i_info(int); |
52 |
|
|
static int print_elist(const char *, u_int); |
53 |
|
|
static int print_nsp(const u_char *, u_int); |
54 |
|
|
static void print_reason(int); |
55 |
|
|
#ifdef PRINT_NSPDATA |
56 |
|
|
static void pdata(u_char *, int); |
57 |
|
|
#endif |
58 |
|
|
|
59 |
|
|
#ifdef HAVE_LIBDNET |
60 |
|
|
extern char *dnet_htoa(struct dn_naddr *); |
61 |
|
|
#endif |
62 |
|
|
|
63 |
|
|
void |
64 |
|
|
decnet_print(const u_char *ap, u_int length, u_int caplen) |
65 |
|
|
{ |
66 |
|
|
static union routehdr rhcopy; |
67 |
|
|
union routehdr *rhp = &rhcopy; |
68 |
|
|
int mflags; |
69 |
|
|
int dst, src, hops; |
70 |
|
|
u_int rhlen, nsplen, pktlen; |
71 |
|
|
const u_char *nspp; |
72 |
|
|
|
73 |
|
|
if (length < sizeof(struct shorthdr)) { |
74 |
|
|
(void)printf("[|decnet]"); |
75 |
|
|
return; |
76 |
|
|
} |
77 |
|
|
|
78 |
|
|
TCHECK2(*ap, sizeof(short)); |
79 |
|
|
pktlen = EXTRACT_LE_16BITS(ap); |
80 |
|
|
if (pktlen < sizeof(struct shorthdr)) { |
81 |
|
|
(void)printf("[|decnet]"); |
82 |
|
|
return; |
83 |
|
|
} |
84 |
|
|
if (pktlen > length) { |
85 |
|
|
(void)printf("[|decnet]"); |
86 |
|
|
return; |
87 |
|
|
} |
88 |
|
|
length = pktlen; |
89 |
|
|
|
90 |
|
|
rhlen = min(length, caplen); |
91 |
|
|
rhlen = min(rhlen, sizeof(*rhp)); |
92 |
|
|
memcpy((char *)rhp, (char *)&(ap[sizeof(short)]), rhlen); |
93 |
|
|
|
94 |
|
|
TCHECK(rhp->rh_short.sh_flags); |
95 |
|
|
mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags); |
96 |
|
|
|
97 |
|
|
if (mflags & RMF_PAD) { |
98 |
|
|
/* pad bytes of some sort in front of message */ |
99 |
|
|
u_int padlen = mflags & RMF_PADMASK; |
100 |
|
|
if (vflag) |
101 |
|
|
(void) printf("[pad:%d] ", padlen); |
102 |
|
|
if (length < padlen + 2) { |
103 |
|
|
(void)printf("[|decnet]"); |
104 |
|
|
return; |
105 |
|
|
} |
106 |
|
|
TCHECK2(ap[sizeof(short)], padlen); |
107 |
|
|
ap += padlen; |
108 |
|
|
length -= padlen; |
109 |
|
|
caplen -= padlen; |
110 |
|
|
rhlen = min(length, caplen); |
111 |
|
|
rhlen = min(rhlen, sizeof(*rhp)); |
112 |
|
|
memcpy((char *)rhp, (char *)&(ap[sizeof(short)]), rhlen); |
113 |
|
|
mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags); |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
if (mflags & RMF_FVER) { |
117 |
|
|
(void) printf("future-version-decnet"); |
118 |
|
|
default_print(ap, min(length, caplen)); |
119 |
|
|
return; |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
/* is it a control message? */ |
123 |
|
|
if (mflags & RMF_CTLMSG) { |
124 |
|
|
if(!print_decnet_ctlmsg(rhp, length, caplen)) |
125 |
|
|
goto trunc; |
126 |
|
|
return; |
127 |
|
|
} |
128 |
|
|
|
129 |
|
|
switch (mflags & RMF_MASK) { |
130 |
|
|
case RMF_LONG: |
131 |
|
|
if (length < sizeof(struct longhdr)) { |
132 |
|
|
(void)printf("[|decnet]"); |
133 |
|
|
return; |
134 |
|
|
} |
135 |
|
|
TCHECK(rhp->rh_long); |
136 |
|
|
dst = |
137 |
|
|
EXTRACT_LE_16BITS(rhp->rh_long.lg_dst.dne_remote.dne_nodeaddr); |
138 |
|
|
src = |
139 |
|
|
EXTRACT_LE_16BITS(rhp->rh_long.lg_src.dne_remote.dne_nodeaddr); |
140 |
|
|
hops = EXTRACT_LE_8BITS(rhp->rh_long.lg_visits); |
141 |
|
|
nspp = &(ap[sizeof(short) + sizeof(struct longhdr)]); |
142 |
|
|
nsplen = length - sizeof(struct longhdr); |
143 |
|
|
break; |
144 |
|
|
case RMF_SHORT: |
145 |
|
|
TCHECK(rhp->rh_short); |
146 |
|
|
dst = EXTRACT_LE_16BITS(rhp->rh_short.sh_dst); |
147 |
|
|
src = EXTRACT_LE_16BITS(rhp->rh_short.sh_src); |
148 |
|
|
hops = (EXTRACT_LE_8BITS(rhp->rh_short.sh_visits) & VIS_MASK)+1; |
149 |
|
|
nspp = &(ap[sizeof(short) + sizeof(struct shorthdr)]); |
150 |
|
|
nsplen = length - sizeof(struct shorthdr); |
151 |
|
|
break; |
152 |
|
|
default: |
153 |
|
|
(void) printf("unknown message flags under mask"); |
154 |
|
|
default_print((u_char *)ap, min(length, caplen)); |
155 |
|
|
return; |
156 |
|
|
} |
157 |
|
|
|
158 |
|
|
(void)printf("%s > %s %d ", |
159 |
|
|
dnaddr_string(src), dnaddr_string(dst), pktlen); |
160 |
|
|
if (vflag) { |
161 |
|
|
if (mflags & RMF_RQR) |
162 |
|
|
(void)printf("RQR "); |
163 |
|
|
if (mflags & RMF_RTS) |
164 |
|
|
(void)printf("RTS "); |
165 |
|
|
if (mflags & RMF_IE) |
166 |
|
|
(void)printf("IE "); |
167 |
|
|
(void)printf("%d hops ", hops); |
168 |
|
|
} |
169 |
|
|
|
170 |
|
|
if (!print_nsp(nspp, nsplen)) |
171 |
|
|
goto trunc; |
172 |
|
|
return; |
173 |
|
|
|
174 |
|
|
trunc: |
175 |
|
|
(void)printf("[|decnet]"); |
176 |
|
|
return; |
177 |
|
|
} |
178 |
|
|
|
179 |
|
|
static int |
180 |
|
|
print_decnet_ctlmsg(const union routehdr *rhp, u_int length, |
181 |
|
|
u_int caplen) |
182 |
|
|
{ |
183 |
|
|
int mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags); |
184 |
|
|
union controlmsg *cmp = (union controlmsg *)rhp; |
185 |
|
|
int src, dst, info, blksize, eco, ueco, hello, other, vers; |
186 |
|
|
etheraddr srcea, rtea; |
187 |
|
|
int priority; |
188 |
|
|
char *rhpx = (char *)rhp; |
189 |
|
|
int ret; |
190 |
|
|
|
191 |
|
|
switch (mflags & RMF_CTLMASK) { |
192 |
|
|
case RMF_INIT: |
193 |
|
|
(void)printf("init "); |
194 |
|
|
if (length < sizeof(struct initmsg)) |
195 |
|
|
goto trunc; |
196 |
|
|
TCHECK(cmp->cm_init); |
197 |
|
|
src = EXTRACT_LE_16BITS(cmp->cm_init.in_src); |
198 |
|
|
info = EXTRACT_LE_8BITS(cmp->cm_init.in_info); |
199 |
|
|
blksize = EXTRACT_LE_16BITS(cmp->cm_init.in_blksize); |
200 |
|
|
vers = EXTRACT_LE_8BITS(cmp->cm_init.in_vers); |
201 |
|
|
eco = EXTRACT_LE_8BITS(cmp->cm_init.in_eco); |
202 |
|
|
ueco = EXTRACT_LE_8BITS(cmp->cm_init.in_ueco); |
203 |
|
|
hello = EXTRACT_LE_16BITS(cmp->cm_init.in_hello); |
204 |
|
|
print_t_info(info); |
205 |
|
|
(void)printf( |
206 |
|
|
"src %sblksize %d vers %d eco %d ueco %d hello %d", |
207 |
|
|
dnaddr_string(src), blksize, vers, eco, ueco, |
208 |
|
|
hello); |
209 |
|
|
|
210 |
|
|
ret = 1; |
211 |
|
|
break; |
212 |
|
|
case RMF_VER: |
213 |
|
|
(void)printf("verification "); |
214 |
|
|
if (length < sizeof(struct verifmsg)) |
215 |
|
|
goto trunc; |
216 |
|
|
TCHECK(cmp->cm_ver); |
217 |
|
|
src = EXTRACT_LE_16BITS(cmp->cm_ver.ve_src); |
218 |
|
|
other = EXTRACT_LE_8BITS(cmp->cm_ver.ve_fcnval); |
219 |
|
|
(void)printf("src %s fcnval %o", dnaddr_string(src), other); |
220 |
|
|
ret = 1; |
221 |
|
|
break; |
222 |
|
|
case RMF_TEST: |
223 |
|
|
(void)printf("test "); |
224 |
|
|
if (length < sizeof(struct testmsg)) |
225 |
|
|
goto trunc; |
226 |
|
|
TCHECK(cmp->cm_test); |
227 |
|
|
src = EXTRACT_LE_16BITS(cmp->cm_test.te_src); |
228 |
|
|
other = EXTRACT_LE_8BITS(cmp->cm_test.te_data); |
229 |
|
|
(void)printf("src %s data %o", dnaddr_string(src), other); |
230 |
|
|
ret = 1; |
231 |
|
|
break; |
232 |
|
|
case RMF_L1ROUT: |
233 |
|
|
(void)printf("lev-1-routing "); |
234 |
|
|
if (length < sizeof(struct l1rout)) |
235 |
|
|
goto trunc; |
236 |
|
|
TCHECK(cmp->cm_l1rou); |
237 |
|
|
src = EXTRACT_LE_16BITS(cmp->cm_l1rou.r1_src); |
238 |
|
|
(void)printf("src %s ", dnaddr_string(src)); |
239 |
|
|
ret = print_l1_routes(&(rhpx[sizeof(struct l1rout)]), |
240 |
|
|
length - sizeof(struct l1rout)); |
241 |
|
|
break; |
242 |
|
|
case RMF_L2ROUT: |
243 |
|
|
(void)printf("lev-2-routing "); |
244 |
|
|
if (length < sizeof(struct l2rout)) |
245 |
|
|
goto trunc; |
246 |
|
|
TCHECK(cmp->cm_l2rout); |
247 |
|
|
src = EXTRACT_LE_16BITS(cmp->cm_l2rout.r2_src); |
248 |
|
|
(void)printf("src %s ", dnaddr_string(src)); |
249 |
|
|
ret = print_l2_routes(&(rhpx[sizeof(struct l2rout)]), |
250 |
|
|
length - sizeof(struct l2rout)); |
251 |
|
|
break; |
252 |
|
|
case RMF_RHELLO: |
253 |
|
|
(void)printf("router-hello "); |
254 |
|
|
if (length < sizeof(struct rhellomsg)) |
255 |
|
|
goto trunc; |
256 |
|
|
TCHECK(cmp->cm_rhello); |
257 |
|
|
vers = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_vers); |
258 |
|
|
eco = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_eco); |
259 |
|
|
ueco = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_ueco); |
260 |
|
|
memcpy((char *)&srcea, (char *)&(cmp->cm_rhello.rh_src), |
261 |
|
|
sizeof(srcea)); |
262 |
|
|
src = EXTRACT_LE_16BITS(srcea.dne_remote.dne_nodeaddr); |
263 |
|
|
info = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_info); |
264 |
|
|
blksize = EXTRACT_LE_16BITS(cmp->cm_rhello.rh_blksize); |
265 |
|
|
priority = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_priority); |
266 |
|
|
hello = EXTRACT_LE_16BITS(cmp->cm_rhello.rh_hello); |
267 |
|
|
print_i_info(info); |
268 |
|
|
(void)printf( |
269 |
|
|
"vers %d eco %d ueco %d src %s blksize %d pri %d hello %d", |
270 |
|
|
vers, eco, ueco, dnaddr_string(src), |
271 |
|
|
blksize, priority, hello); |
272 |
|
|
ret = print_elist(&(rhpx[sizeof(struct rhellomsg)]), |
273 |
|
|
length - sizeof(struct rhellomsg)); |
274 |
|
|
break; |
275 |
|
|
case RMF_EHELLO: |
276 |
|
|
(void)printf("endnode-hello "); |
277 |
|
|
if (length < sizeof(struct ehellomsg)) |
278 |
|
|
goto trunc; |
279 |
|
|
TCHECK(cmp->cm_ehello); |
280 |
|
|
vers = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_vers); |
281 |
|
|
eco = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_eco); |
282 |
|
|
ueco = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_ueco); |
283 |
|
|
memcpy((char *)&srcea, (char *)&(cmp->cm_ehello.eh_src), |
284 |
|
|
sizeof(srcea)); |
285 |
|
|
src = EXTRACT_LE_16BITS(srcea.dne_remote.dne_nodeaddr); |
286 |
|
|
info = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_info); |
287 |
|
|
blksize = EXTRACT_LE_16BITS(cmp->cm_ehello.eh_blksize); |
288 |
|
|
/*seed*/ |
289 |
|
|
memcpy((char *)&rtea, (char *)&(cmp->cm_ehello.eh_router), |
290 |
|
|
sizeof(rtea)); |
291 |
|
|
dst = EXTRACT_LE_16BITS(rtea.dne_remote.dne_nodeaddr); |
292 |
|
|
hello = EXTRACT_LE_16BITS(cmp->cm_ehello.eh_hello); |
293 |
|
|
other = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_data); |
294 |
|
|
print_i_info(info); |
295 |
|
|
(void)printf( |
296 |
|
|
"vers %d eco %d ueco %d src %s blksize %d rtr %s hello %d data %o", |
297 |
|
|
vers, eco, ueco, dnaddr_string(src), |
298 |
|
|
blksize, dnaddr_string(dst), hello, other); |
299 |
|
|
ret = 1; |
300 |
|
|
break; |
301 |
|
|
|
302 |
|
|
default: |
303 |
|
|
(void)printf("unknown control message"); |
304 |
|
|
default_print((u_char *)rhp, min(length, caplen)); |
305 |
|
|
ret = 1; |
306 |
|
|
break; |
307 |
|
|
} |
308 |
|
|
return (ret); |
309 |
|
|
|
310 |
|
|
trunc: |
311 |
|
|
return (0); |
312 |
|
|
} |
313 |
|
|
|
314 |
|
|
static void |
315 |
|
|
print_t_info(int info) |
316 |
|
|
{ |
317 |
|
|
int ntype = info & 3; |
318 |
|
|
switch (ntype) { |
319 |
|
|
case 0: (void)printf("reserved-ntype? "); break; |
320 |
|
|
case TI_L2ROUT: (void)printf("l2rout "); break; |
321 |
|
|
case TI_L1ROUT: (void)printf("l1rout "); break; |
322 |
|
|
case TI_ENDNODE: (void)printf("endnode "); break; |
323 |
|
|
} |
324 |
|
|
if (info & TI_VERIF) |
325 |
|
|
(void)printf("verif "); |
326 |
|
|
if (info & TI_BLOCK) |
327 |
|
|
(void)printf("blo "); |
328 |
|
|
} |
329 |
|
|
|
330 |
|
|
static int |
331 |
|
|
print_l1_routes(const char *rp, u_int len) |
332 |
|
|
{ |
333 |
|
|
int count; |
334 |
|
|
int id; |
335 |
|
|
int info; |
336 |
|
|
|
337 |
|
|
/* The last short is a checksum */ |
338 |
|
|
while (len > (3 * sizeof(short))) { |
339 |
|
|
TCHECK2(*rp, 3 * sizeof(short)); |
340 |
|
|
count = EXTRACT_LE_16BITS(rp); |
341 |
|
|
if (count > 1024) |
342 |
|
|
return (1); /* seems to be bogus from here on */ |
343 |
|
|
rp += sizeof(short); |
344 |
|
|
len -= sizeof(short); |
345 |
|
|
id = EXTRACT_LE_16BITS(rp); |
346 |
|
|
rp += sizeof(short); |
347 |
|
|
len -= sizeof(short); |
348 |
|
|
info = EXTRACT_LE_16BITS(rp); |
349 |
|
|
rp += sizeof(short); |
350 |
|
|
len -= sizeof(short); |
351 |
|
|
(void)printf("{ids %d-%d cost %d hops %d} ", id, id + count, |
352 |
|
|
RI_COST(info), RI_HOPS(info)); |
353 |
|
|
} |
354 |
|
|
return (1); |
355 |
|
|
|
356 |
|
|
trunc: |
357 |
|
|
return (0); |
358 |
|
|
} |
359 |
|
|
|
360 |
|
|
static int |
361 |
|
|
print_l2_routes(const char *rp, u_int len) |
362 |
|
|
{ |
363 |
|
|
int count; |
364 |
|
|
int area; |
365 |
|
|
int info; |
366 |
|
|
|
367 |
|
|
/* The last short is a checksum */ |
368 |
|
|
while (len > (3 * sizeof(short))) { |
369 |
|
|
TCHECK2(*rp, 3 * sizeof(short)); |
370 |
|
|
count = EXTRACT_LE_16BITS(rp); |
371 |
|
|
if (count > 1024) |
372 |
|
|
return (1); /* seems to be bogus from here on */ |
373 |
|
|
rp += sizeof(short); |
374 |
|
|
len -= sizeof(short); |
375 |
|
|
area = EXTRACT_LE_16BITS(rp); |
376 |
|
|
rp += sizeof(short); |
377 |
|
|
len -= sizeof(short); |
378 |
|
|
info = EXTRACT_LE_16BITS(rp); |
379 |
|
|
rp += sizeof(short); |
380 |
|
|
len -= sizeof(short); |
381 |
|
|
(void)printf("{areas %d-%d cost %d hops %d} ", area, area + count, |
382 |
|
|
RI_COST(info), RI_HOPS(info)); |
383 |
|
|
} |
384 |
|
|
return (1); |
385 |
|
|
|
386 |
|
|
trunc: |
387 |
|
|
return (0); |
388 |
|
|
} |
389 |
|
|
|
390 |
|
|
static void |
391 |
|
|
print_i_info(int info) |
392 |
|
|
{ |
393 |
|
|
int ntype = info & II_TYPEMASK; |
394 |
|
|
switch (ntype) { |
395 |
|
|
case 0: (void)printf("reserved-ntype? "); break; |
396 |
|
|
case II_L2ROUT: (void)printf("l2rout "); break; |
397 |
|
|
case II_L1ROUT: (void)printf("l1rout "); break; |
398 |
|
|
case II_ENDNODE: (void)printf("endnode "); break; |
399 |
|
|
} |
400 |
|
|
if (info & II_VERIF) |
401 |
|
|
(void)printf("verif "); |
402 |
|
|
if (info & II_NOMCAST) |
403 |
|
|
(void)printf("nomcast "); |
404 |
|
|
if (info & II_BLOCK) |
405 |
|
|
(void)printf("blo "); |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
static int |
409 |
|
|
print_elist(const char *elp, u_int len) |
410 |
|
|
{ |
411 |
|
|
/* Not enough examples available for me to debug this */ |
412 |
|
|
return (1); |
413 |
|
|
} |
414 |
|
|
|
415 |
|
|
static int |
416 |
|
|
print_nsp(const u_char *nspp, u_int nsplen) |
417 |
|
|
{ |
418 |
|
|
const struct nsphdr *nsphp = (struct nsphdr *)nspp; |
419 |
|
|
int dst, src, flags; |
420 |
|
|
|
421 |
|
|
if (nsplen < sizeof(struct nsphdr)) |
422 |
|
|
goto trunc; |
423 |
|
|
TCHECK(*nsphp); |
424 |
|
|
flags = EXTRACT_LE_8BITS(nsphp->nh_flags); |
425 |
|
|
dst = EXTRACT_LE_16BITS(nsphp->nh_dst); |
426 |
|
|
src = EXTRACT_LE_16BITS(nsphp->nh_src); |
427 |
|
|
|
428 |
|
|
switch (flags & NSP_TYPEMASK) { |
429 |
|
|
case MFT_DATA: |
430 |
|
|
switch (flags & NSP_SUBMASK) { |
431 |
|
|
case MFS_BOM: |
432 |
|
|
case MFS_MOM: |
433 |
|
|
case MFS_EOM: |
434 |
|
|
case MFS_BOM+MFS_EOM: |
435 |
|
|
printf("data %d>%d ", src, dst); |
436 |
|
|
{ |
437 |
|
|
struct seghdr *shp = (struct seghdr *)nspp; |
438 |
|
|
int ack; |
439 |
|
|
#ifdef PRINT_NSPDATA |
440 |
|
|
u_char *dp; |
441 |
|
|
#endif |
442 |
|
|
u_int data_off = sizeof(struct minseghdr); |
443 |
|
|
|
444 |
|
|
if (nsplen < data_off) |
445 |
|
|
goto trunc; |
446 |
|
|
TCHECK(shp->sh_seq[0]); |
447 |
|
|
ack = EXTRACT_LE_16BITS(shp->sh_seq[0]); |
448 |
|
|
if (ack & SGQ_ACK) { /* acknum field */ |
449 |
|
|
if ((ack & SGQ_NAK) == SGQ_NAK) |
450 |
|
|
(void)printf("nak %d ", ack & SGQ_MASK); |
451 |
|
|
else |
452 |
|
|
(void)printf("ack %d ", ack & SGQ_MASK); |
453 |
|
|
data_off += sizeof(short); |
454 |
|
|
if (nsplen < data_off) |
455 |
|
|
goto trunc; |
456 |
|
|
TCHECK(shp->sh_seq[1]); |
457 |
|
|
ack = EXTRACT_LE_16BITS(shp->sh_seq[1]); |
458 |
|
|
if (ack & SGQ_OACK) { /* ackoth field */ |
459 |
|
|
if ((ack & SGQ_ONAK) == SGQ_ONAK) |
460 |
|
|
(void)printf("onak %d ", ack & SGQ_MASK); |
461 |
|
|
else |
462 |
|
|
(void)printf("oack %d ", ack & SGQ_MASK); |
463 |
|
|
data_off += sizeof(short); |
464 |
|
|
if (nsplen < data_off) |
465 |
|
|
goto trunc; |
466 |
|
|
TCHECK(shp->sh_seq[2]); |
467 |
|
|
ack = EXTRACT_LE_16BITS(shp->sh_seq[2]); |
468 |
|
|
} |
469 |
|
|
} |
470 |
|
|
(void)printf("seg %d ", ack & SGQ_MASK); |
471 |
|
|
#ifdef PRINT_NSPDATA |
472 |
|
|
if (nsplen > data_off) { |
473 |
|
|
dp = &(nspp[data_off]); |
474 |
|
|
TCHECK2(*dp, nsplen - data_off); |
475 |
|
|
pdata(dp, nsplen - data_off); |
476 |
|
|
} |
477 |
|
|
#endif |
478 |
|
|
} |
479 |
|
|
break; |
480 |
|
|
case MFS_ILS+MFS_INT: |
481 |
|
|
printf("intr "); |
482 |
|
|
{ |
483 |
|
|
struct seghdr *shp = (struct seghdr *)nspp; |
484 |
|
|
int ack; |
485 |
|
|
#ifdef PRINT_NSPDATA |
486 |
|
|
u_char *dp; |
487 |
|
|
#endif |
488 |
|
|
u_int data_off = sizeof(struct minseghdr); |
489 |
|
|
|
490 |
|
|
if (nsplen < data_off) |
491 |
|
|
goto trunc; |
492 |
|
|
TCHECK(shp->sh_seq[0]); |
493 |
|
|
ack = EXTRACT_LE_16BITS(shp->sh_seq[0]); |
494 |
|
|
if (ack & SGQ_ACK) { /* acknum field */ |
495 |
|
|
if ((ack & SGQ_NAK) == SGQ_NAK) |
496 |
|
|
(void)printf("nak %d ", ack & SGQ_MASK); |
497 |
|
|
else |
498 |
|
|
(void)printf("ack %d ", ack & SGQ_MASK); |
499 |
|
|
data_off += sizeof(short); |
500 |
|
|
if (nsplen < data_off) |
501 |
|
|
goto trunc; |
502 |
|
|
TCHECK(shp->sh_seq[1]); |
503 |
|
|
ack = EXTRACT_LE_16BITS(shp->sh_seq[1]); |
504 |
|
|
if (ack & SGQ_OACK) { /* ackdat field */ |
505 |
|
|
if ((ack & SGQ_ONAK) == SGQ_ONAK) |
506 |
|
|
(void)printf("nakdat %d ", ack & SGQ_MASK); |
507 |
|
|
else |
508 |
|
|
(void)printf("ackdat %d ", ack & SGQ_MASK); |
509 |
|
|
data_off += sizeof(short); |
510 |
|
|
if (nsplen < data_off) |
511 |
|
|
goto trunc; |
512 |
|
|
TCHECK(shp->sh_seq[2]); |
513 |
|
|
ack = EXTRACT_LE_16BITS(shp->sh_seq[2]); |
514 |
|
|
} |
515 |
|
|
} |
516 |
|
|
(void)printf("seg %d ", ack & SGQ_MASK); |
517 |
|
|
#ifdef PRINT_NSPDATA |
518 |
|
|
if (nsplen > data_off) { |
519 |
|
|
dp = &(nspp[data_off]); |
520 |
|
|
TCHECK2(*dp, nsplen - data_off); |
521 |
|
|
pdata(dp, nsplen - data_off); |
522 |
|
|
} |
523 |
|
|
#endif |
524 |
|
|
} |
525 |
|
|
break; |
526 |
|
|
case MFS_ILS: |
527 |
|
|
(void)printf("link-service %d>%d ", src, dst); |
528 |
|
|
{ |
529 |
|
|
struct seghdr *shp = (struct seghdr *)nspp; |
530 |
|
|
struct lsmsg *lsmp = |
531 |
|
|
(struct lsmsg *)&(nspp[sizeof(struct seghdr)]); |
532 |
|
|
int ack; |
533 |
|
|
int lsflags, fcval; |
534 |
|
|
|
535 |
|
|
if (nsplen < sizeof(struct seghdr) + sizeof(struct lsmsg)) |
536 |
|
|
goto trunc; |
537 |
|
|
TCHECK(shp->sh_seq[0]); |
538 |
|
|
ack = EXTRACT_LE_16BITS(shp->sh_seq[0]); |
539 |
|
|
if (ack & SGQ_ACK) { /* acknum field */ |
540 |
|
|
if ((ack & SGQ_NAK) == SGQ_NAK) |
541 |
|
|
(void)printf("nak %d ", ack & SGQ_MASK); |
542 |
|
|
else |
543 |
|
|
(void)printf("ack %d ", ack & SGQ_MASK); |
544 |
|
|
TCHECK(shp->sh_seq[1]); |
545 |
|
|
ack = EXTRACT_LE_16BITS(shp->sh_seq[1]); |
546 |
|
|
if (ack & SGQ_OACK) { /* ackdat field */ |
547 |
|
|
if ((ack & SGQ_ONAK) == SGQ_ONAK) |
548 |
|
|
(void)printf("nakdat %d ", ack & SGQ_MASK); |
549 |
|
|
else |
550 |
|
|
(void)printf("ackdat %d ", ack & SGQ_MASK); |
551 |
|
|
TCHECK(shp->sh_seq[2]); |
552 |
|
|
ack = EXTRACT_LE_16BITS(shp->sh_seq[2]); |
553 |
|
|
} |
554 |
|
|
} |
555 |
|
|
(void)printf("seg %d ", ack & SGQ_MASK); |
556 |
|
|
TCHECK(*lsmp); |
557 |
|
|
lsflags = EXTRACT_LE_8BITS(lsmp->ls_lsflags); |
558 |
|
|
fcval = EXTRACT_LE_8BITS(lsmp->ls_fcval); |
559 |
|
|
switch (lsflags & LSI_MASK) { |
560 |
|
|
case LSI_DATA: |
561 |
|
|
(void)printf("dat seg count %d ", fcval); |
562 |
|
|
switch (lsflags & LSM_MASK) { |
563 |
|
|
case LSM_NOCHANGE: |
564 |
|
|
break; |
565 |
|
|
case LSM_DONOTSEND: |
566 |
|
|
(void)printf("donotsend-data "); |
567 |
|
|
break; |
568 |
|
|
case LSM_SEND: |
569 |
|
|
(void)printf("send-data "); |
570 |
|
|
break; |
571 |
|
|
default: |
572 |
|
|
(void)printf("reserved-fcmod? %x", lsflags); |
573 |
|
|
break; |
574 |
|
|
} |
575 |
|
|
break; |
576 |
|
|
case LSI_INTR: |
577 |
|
|
(void)printf("intr req count %d ", fcval); |
578 |
|
|
break; |
579 |
|
|
default: |
580 |
|
|
(void)printf("reserved-fcval-int? %x", lsflags); |
581 |
|
|
break; |
582 |
|
|
} |
583 |
|
|
} |
584 |
|
|
break; |
585 |
|
|
default: |
586 |
|
|
(void)printf("reserved-subtype? %x %d > %d", flags, src, dst); |
587 |
|
|
break; |
588 |
|
|
} |
589 |
|
|
break; |
590 |
|
|
case MFT_ACK: |
591 |
|
|
switch (flags & NSP_SUBMASK) { |
592 |
|
|
case MFS_DACK: |
593 |
|
|
(void)printf("data-ack %d>%d ", src, dst); |
594 |
|
|
{ |
595 |
|
|
struct ackmsg *amp = (struct ackmsg *)nspp; |
596 |
|
|
int ack; |
597 |
|
|
|
598 |
|
|
if (nsplen < sizeof(struct ackmsg)) |
599 |
|
|
goto trunc; |
600 |
|
|
TCHECK(*amp); |
601 |
|
|
ack = EXTRACT_LE_16BITS(amp->ak_acknum[0]); |
602 |
|
|
if (ack & SGQ_ACK) { /* acknum field */ |
603 |
|
|
if ((ack & SGQ_NAK) == SGQ_NAK) |
604 |
|
|
(void)printf("nak %d ", ack & SGQ_MASK); |
605 |
|
|
else |
606 |
|
|
(void)printf("ack %d ", ack & SGQ_MASK); |
607 |
|
|
ack = EXTRACT_LE_16BITS(amp->ak_acknum[1]); |
608 |
|
|
if (ack & SGQ_OACK) { /* ackoth field */ |
609 |
|
|
if ((ack & SGQ_ONAK) == SGQ_ONAK) |
610 |
|
|
(void)printf("onak %d ", ack & SGQ_MASK); |
611 |
|
|
else |
612 |
|
|
(void)printf("oack %d ", ack & SGQ_MASK); |
613 |
|
|
} |
614 |
|
|
} |
615 |
|
|
} |
616 |
|
|
break; |
617 |
|
|
case MFS_IACK: |
618 |
|
|
(void)printf("ils-ack %d>%d ", src, dst); |
619 |
|
|
{ |
620 |
|
|
struct ackmsg *amp = (struct ackmsg *)nspp; |
621 |
|
|
int ack; |
622 |
|
|
|
623 |
|
|
if (nsplen < sizeof(struct ackmsg)) |
624 |
|
|
goto trunc; |
625 |
|
|
TCHECK(*amp); |
626 |
|
|
ack = EXTRACT_LE_16BITS(amp->ak_acknum[0]); |
627 |
|
|
if (ack & SGQ_ACK) { /* acknum field */ |
628 |
|
|
if ((ack & SGQ_NAK) == SGQ_NAK) |
629 |
|
|
(void)printf("nak %d ", ack & SGQ_MASK); |
630 |
|
|
else |
631 |
|
|
(void)printf("ack %d ", ack & SGQ_MASK); |
632 |
|
|
TCHECK(amp->ak_acknum[1]); |
633 |
|
|
ack = EXTRACT_LE_16BITS(amp->ak_acknum[1]); |
634 |
|
|
if (ack & SGQ_OACK) { /* ackdat field */ |
635 |
|
|
if ((ack & SGQ_ONAK) == SGQ_ONAK) |
636 |
|
|
(void)printf("nakdat %d ", ack & SGQ_MASK); |
637 |
|
|
else |
638 |
|
|
(void)printf("ackdat %d ", ack & SGQ_MASK); |
639 |
|
|
} |
640 |
|
|
} |
641 |
|
|
} |
642 |
|
|
break; |
643 |
|
|
case MFS_CACK: |
644 |
|
|
(void)printf("conn-ack %d", dst); |
645 |
|
|
break; |
646 |
|
|
default: |
647 |
|
|
(void)printf("reserved-acktype? %x %d > %d", flags, src, dst); |
648 |
|
|
break; |
649 |
|
|
} |
650 |
|
|
break; |
651 |
|
|
case MFT_CTL: |
652 |
|
|
switch (flags & NSP_SUBMASK) { |
653 |
|
|
case MFS_CI: |
654 |
|
|
case MFS_RCI: |
655 |
|
|
if ((flags & NSP_SUBMASK) == MFS_CI) |
656 |
|
|
(void)printf("conn-initiate "); |
657 |
|
|
else |
658 |
|
|
(void)printf("retrans-conn-initiate "); |
659 |
|
|
(void)printf("%d>%d ", src, dst); |
660 |
|
|
{ |
661 |
|
|
struct cimsg *cimp = (struct cimsg *)nspp; |
662 |
|
|
int services, info, segsize; |
663 |
|
|
#ifdef PRINT_NSPDATA |
664 |
|
|
u_char *dp; |
665 |
|
|
#endif |
666 |
|
|
|
667 |
|
|
if (nsplen < sizeof(struct cimsg)) |
668 |
|
|
goto trunc; |
669 |
|
|
TCHECK(*cimp); |
670 |
|
|
services = EXTRACT_LE_8BITS(cimp->ci_services); |
671 |
|
|
info = EXTRACT_LE_8BITS(cimp->ci_info); |
672 |
|
|
segsize = EXTRACT_LE_16BITS(cimp->ci_segsize); |
673 |
|
|
|
674 |
|
|
switch (services & COS_MASK) { |
675 |
|
|
case COS_NONE: |
676 |
|
|
break; |
677 |
|
|
case COS_SEGMENT: |
678 |
|
|
(void)printf("seg "); |
679 |
|
|
break; |
680 |
|
|
case COS_MESSAGE: |
681 |
|
|
(void)printf("msg "); |
682 |
|
|
break; |
683 |
|
|
case COS_CRYPTSER: |
684 |
|
|
(void)printf("crypt "); |
685 |
|
|
break; |
686 |
|
|
} |
687 |
|
|
switch (info & COI_MASK) { |
688 |
|
|
case COI_32: |
689 |
|
|
(void)printf("ver 3.2 "); |
690 |
|
|
break; |
691 |
|
|
case COI_31: |
692 |
|
|
(void)printf("ver 3.1 "); |
693 |
|
|
break; |
694 |
|
|
case COI_40: |
695 |
|
|
(void)printf("ver 4.0 "); |
696 |
|
|
break; |
697 |
|
|
case COI_41: |
698 |
|
|
(void)printf("ver 4.1 "); |
699 |
|
|
break; |
700 |
|
|
} |
701 |
|
|
(void)printf("segsize %d ", segsize); |
702 |
|
|
#ifdef PRINT_NSPDATA |
703 |
|
|
if (nsplen > sizeof(struct cimsg)) { |
704 |
|
|
dp = &(nspp[sizeof(struct cimsg)]); |
705 |
|
|
TCHECK2(*dp, nsplen - sizeof(struct cimsg)); |
706 |
|
|
pdata(dp, nsplen - sizeof(struct cimsg)); |
707 |
|
|
} |
708 |
|
|
#endif |
709 |
|
|
} |
710 |
|
|
break; |
711 |
|
|
case MFS_CC: |
712 |
|
|
(void)printf("conn-confirm %d>%d ", src, dst); |
713 |
|
|
{ |
714 |
|
|
struct ccmsg *ccmp = (struct ccmsg *)nspp; |
715 |
|
|
int services, info; |
716 |
|
|
u_int segsize, optlen; |
717 |
|
|
#ifdef PRINT_NSPDATA |
718 |
|
|
u_char *dp; |
719 |
|
|
#endif |
720 |
|
|
|
721 |
|
|
if (nsplen < sizeof(struct ccmsg)) |
722 |
|
|
goto trunc; |
723 |
|
|
TCHECK(*ccmp); |
724 |
|
|
services = EXTRACT_LE_8BITS(ccmp->cc_services); |
725 |
|
|
info = EXTRACT_LE_8BITS(ccmp->cc_info); |
726 |
|
|
segsize = EXTRACT_LE_16BITS(ccmp->cc_segsize); |
727 |
|
|
optlen = EXTRACT_LE_8BITS(ccmp->cc_optlen); |
728 |
|
|
|
729 |
|
|
switch (services & COS_MASK) { |
730 |
|
|
case COS_NONE: |
731 |
|
|
break; |
732 |
|
|
case COS_SEGMENT: |
733 |
|
|
(void)printf("seg "); |
734 |
|
|
break; |
735 |
|
|
case COS_MESSAGE: |
736 |
|
|
(void)printf("msg "); |
737 |
|
|
break; |
738 |
|
|
case COS_CRYPTSER: |
739 |
|
|
(void)printf("crypt "); |
740 |
|
|
break; |
741 |
|
|
} |
742 |
|
|
switch (info & COI_MASK) { |
743 |
|
|
case COI_32: |
744 |
|
|
(void)printf("ver 3.2 "); |
745 |
|
|
break; |
746 |
|
|
case COI_31: |
747 |
|
|
(void)printf("ver 3.1 "); |
748 |
|
|
break; |
749 |
|
|
case COI_40: |
750 |
|
|
(void)printf("ver 4.0 "); |
751 |
|
|
break; |
752 |
|
|
case COI_41: |
753 |
|
|
(void)printf("ver 4.1 "); |
754 |
|
|
break; |
755 |
|
|
} |
756 |
|
|
(void)printf("segsize %d ", segsize); |
757 |
|
|
if (optlen) { |
758 |
|
|
(void)printf("optlen %d ", optlen); |
759 |
|
|
#ifdef PRINT_NSPDATA |
760 |
|
|
if (optlen > nsplen - sizeof(struct ccmsg)) |
761 |
|
|
goto trunc; |
762 |
|
|
dp = &(nspp[sizeof(struct ccmsg)]); |
763 |
|
|
TCHECK2(*dp, optlen); |
764 |
|
|
pdata(dp, optlen); |
765 |
|
|
#endif |
766 |
|
|
} |
767 |
|
|
} |
768 |
|
|
break; |
769 |
|
|
case MFS_DI: |
770 |
|
|
(void)printf("disconn-initiate %d>%d ", src, dst); |
771 |
|
|
{ |
772 |
|
|
struct dimsg *dimp = (struct dimsg *)nspp; |
773 |
|
|
int reason; |
774 |
|
|
u_int optlen; |
775 |
|
|
#ifdef PRINT_NSPDATA |
776 |
|
|
u_char *dp; |
777 |
|
|
#endif |
778 |
|
|
|
779 |
|
|
if (nsplen < sizeof(struct dimsg)) |
780 |
|
|
goto trunc; |
781 |
|
|
TCHECK(*dimp); |
782 |
|
|
reason = EXTRACT_LE_16BITS(dimp->di_reason); |
783 |
|
|
optlen = EXTRACT_LE_8BITS(dimp->di_optlen); |
784 |
|
|
|
785 |
|
|
print_reason(reason); |
786 |
|
|
if (optlen) { |
787 |
|
|
(void)printf("optlen %d ", optlen); |
788 |
|
|
#ifdef PRINT_NSPDATA |
789 |
|
|
if (optlen > nsplen - sizeof(struct dimsg)) |
790 |
|
|
goto trunc; |
791 |
|
|
dp = &(nspp[sizeof(struct dimsg)]); |
792 |
|
|
TCHECK2(*dp, optlen); |
793 |
|
|
pdata(dp, optlen); |
794 |
|
|
#endif |
795 |
|
|
} |
796 |
|
|
} |
797 |
|
|
break; |
798 |
|
|
case MFS_DC: |
799 |
|
|
(void)printf("disconn-confirm %d>%d ", src, dst); |
800 |
|
|
{ |
801 |
|
|
struct dcmsg *dcmp = (struct dcmsg *)nspp; |
802 |
|
|
int reason; |
803 |
|
|
|
804 |
|
|
TCHECK(*dcmp); |
805 |
|
|
reason = EXTRACT_LE_16BITS(dcmp->dc_reason); |
806 |
|
|
|
807 |
|
|
print_reason(reason); |
808 |
|
|
} |
809 |
|
|
break; |
810 |
|
|
default: |
811 |
|
|
(void)printf("reserved-ctltype? %x %d > %d", flags, src, dst); |
812 |
|
|
break; |
813 |
|
|
} |
814 |
|
|
break; |
815 |
|
|
default: |
816 |
|
|
(void)printf("reserved-type? %x %d > %d", flags, src, dst); |
817 |
|
|
break; |
818 |
|
|
} |
819 |
|
|
return (1); |
820 |
|
|
|
821 |
|
|
trunc: |
822 |
|
|
return (0); |
823 |
|
|
} |
824 |
|
|
|
825 |
|
|
static struct tok reason2str[] = { |
826 |
|
|
{ UC_OBJREJECT, "object rejected connect" }, |
827 |
|
|
{ UC_RESOURCES, "insufficient resources" }, |
828 |
|
|
{ UC_NOSUCHNODE, "unrecognized node name" }, |
829 |
|
|
{ DI_SHUT, "node is shutting down" }, |
830 |
|
|
{ UC_NOSUCHOBJ, "unrecognized object" }, |
831 |
|
|
{ UC_INVOBJFORMAT, "invalid object name format" }, |
832 |
|
|
{ UC_OBJTOOBUSY, "object too busy" }, |
833 |
|
|
{ DI_PROTOCOL, "protocol error discovered" }, |
834 |
|
|
{ DI_TPA, "third party abort" }, |
835 |
|
|
{ UC_USERABORT, "user abort" }, |
836 |
|
|
{ UC_INVNODEFORMAT, "invalid node name format" }, |
837 |
|
|
{ UC_LOCALSHUT, "local node shutting down" }, |
838 |
|
|
{ DI_LOCALRESRC, "insufficient local resources" }, |
839 |
|
|
{ DI_REMUSERRESRC, "insufficient remote user resources" }, |
840 |
|
|
{ UC_ACCESSREJECT, "invalid access control information" }, |
841 |
|
|
{ DI_BADACCNT, "bad ACCOUNT information" }, |
842 |
|
|
{ UC_NORESPONSE, "no response from object" }, |
843 |
|
|
{ UC_UNREACHABLE, "node unreachable" }, |
844 |
|
|
{ DC_NOLINK, "no link terminate" }, |
845 |
|
|
{ DC_COMPLETE, "disconnect complete" }, |
846 |
|
|
{ DI_BADIMAGE, "bad image data in connect" }, |
847 |
|
|
{ DI_SERVMISMATCH, "cryptographic service mismatch" }, |
848 |
|
|
{ 0, NULL } |
849 |
|
|
}; |
850 |
|
|
|
851 |
|
|
static void |
852 |
|
|
print_reason(int reason) |
853 |
|
|
{ |
854 |
|
|
printf("%s ", tok2str(reason2str, "reason-%d", reason)); |
855 |
|
|
} |
856 |
|
|
|
857 |
|
|
char * |
858 |
|
|
dnnum_string(u_short dnaddr) |
859 |
|
|
{ |
860 |
|
|
char *str; |
861 |
|
|
int area = (u_short)(dnaddr & AREAMASK) >> AREASHIFT; |
862 |
|
|
int node = dnaddr & NODEMASK; |
863 |
|
|
int len = sizeof("00.0000"); |
864 |
|
|
|
865 |
|
|
str = malloc(len); |
866 |
|
|
if (str == NULL) |
867 |
|
|
error("dnnum_string: malloc"); |
868 |
|
|
snprintf(str, len, "%d.%d", area, node); |
869 |
|
|
return(str); |
870 |
|
|
} |
871 |
|
|
|
872 |
|
|
char * |
873 |
|
|
dnname_string(u_short dnaddr) |
874 |
|
|
{ |
875 |
|
|
#ifdef HAVE_LIBDNET |
876 |
|
|
struct dn_naddr dna; |
877 |
|
|
|
878 |
|
|
dna.a_len = sizeof(short); |
879 |
|
|
memcpy((char *)dna.a_addr, (char *)&dnaddr, sizeof(short)); |
880 |
|
|
return (savestr(dnet_htoa(&dna))); |
881 |
|
|
#else |
882 |
|
|
return(dnnum_string(dnaddr)); /* punt */ |
883 |
|
|
#endif |
884 |
|
|
} |
885 |
|
|
|
886 |
|
|
#ifdef PRINT_NSPDATA |
887 |
|
|
static void |
888 |
|
|
pdata(u_char *dp, u_int maxlen) |
889 |
|
|
{ |
890 |
|
|
int c; |
891 |
|
|
u_int x = maxlen; |
892 |
|
|
|
893 |
|
|
while (x-- > 0) { |
894 |
|
|
c = (unsigned char)*dp++; |
895 |
|
|
if (isprint(c)) |
896 |
|
|
putchar(c); |
897 |
|
|
else |
898 |
|
|
printf("\\%o", c & 0xFF); |
899 |
|
|
} |
900 |
|
|
} |
901 |
|
|
#endif |