print-wb.c revision 1.11 1 /*
2 * Copyright (c) 1993, 1994, 1995, 1996
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: print-wb.c,v 1.11 2023/08/17 20:19:40 christos Exp $");
25 #endif
26
27 /* \summary: White Board printer */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include "netdissect-stdinc.h"
34
35 #define ND_LONGJMP_FROM_TCHECK
36 #include "netdissect.h"
37 #include "addrtoname.h"
38 #include "extract.h"
39
40
41 #if 0
42 /*
43 * Largest packet size. Everything should fit within this space.
44 * For instance, multiline objects are sent piecewise.
45 */
46 #define MAXFRAMESIZE 1024
47 #endif
48
49 /*
50 * Multiple drawing ops can be sent in one packet. Each one starts on a
51 * an even multiple of DOP_ALIGN bytes, which must be a power of two.
52 */
53 #define DOP_ALIGN 4
54 #define DOP_ROUNDUP(x) roundup2(x, DOP_ALIGN)
55 #define DOP_NEXT(d)\
56 ((const struct dophdr *)((const u_char *)(d) + \
57 DOP_ROUNDUP(GET_BE_U_2((d)->dh_len) + sizeof(*(d)))))
58
59 /*
60 * Format of the whiteboard packet header.
61 * The transport level header.
62 */
63 struct pkt_hdr {
64 nd_uint32_t ph_src; /* site id of source */
65 nd_uint32_t ph_ts; /* time stamp (for skew computation) */
66 nd_uint16_t ph_version; /* version number */
67 nd_uint8_t ph_type; /* message type */
68 nd_uint8_t ph_flags; /* message flags */
69 };
70
71 /* Packet types */
72 #define PT_DRAWOP 0 /* drawing operation */
73 #define PT_ID 1 /* announcement packet */
74 #define PT_RREQ 2 /* repair request */
75 #define PT_RREP 3 /* repair reply */
76 #define PT_KILL 4 /* terminate participation */
77 #define PT_PREQ 5 /* page vector request */
78 #define PT_PREP 7 /* page vector reply */
79
80 #if 0
81 #ifdef PF_USER
82 #undef PF_USER /* {Digital,Tru64} UNIX define this, alas */
83 #endif
84
85 /* flags */
86 #define PF_USER 0x01 /* hint that packet has interactive data */
87 #define PF_VIS 0x02 /* only visible ops wanted */
88 #endif
89
90 struct PageID {
91 nd_uint32_t p_sid; /* session id of initiator */
92 nd_uint32_t p_uid; /* page number */
93 };
94
95 struct dophdr {
96 nd_uint32_t dh_ts; /* sender's timestamp */
97 nd_uint16_t dh_len; /* body length */
98 nd_uint8_t dh_flags;
99 nd_uint8_t dh_type; /* body type */
100 /* body follows */
101 };
102 /*
103 * Drawing op sub-types.
104 */
105 #define DT_RECT 2
106 #define DT_LINE 3
107 #define DT_ML 4
108 #define DT_DEL 5
109 #define DT_XFORM 6
110 #define DT_ELL 7
111 #define DT_CHAR 8
112 #define DT_STR 9
113 #define DT_NOP 10
114 #define DT_PSCODE 11
115 #define DT_PSCOMP 12
116 #define DT_REF 13
117 #define DT_SKIP 14
118 #define DT_HOLE 15
119 static const struct tok dop_str[] = {
120 { DT_RECT, "RECT" },
121 { DT_LINE, "LINE" },
122 { DT_ML, "ML" },
123 { DT_DEL, "DEL" },
124 { DT_XFORM, "XFORM" },
125 { DT_ELL, "ELL" },
126 { DT_CHAR, "CHAR" },
127 { DT_STR, "STR" },
128 { DT_NOP, "NOP" },
129 { DT_PSCODE, "PSCODE" },
130 { DT_PSCOMP, "PSCOMP" },
131 { DT_REF, "REF" },
132 { DT_SKIP, "SKIP" },
133 { DT_HOLE, "HOLE" },
134 { 0, NULL }
135 };
136
137 /*
138 * A drawing operation.
139 */
140 struct pkt_dop {
141 struct PageID pd_page; /* page that operations apply to */
142 nd_uint32_t pd_sseq; /* start sequence number */
143 nd_uint32_t pd_eseq; /* end sequence number */
144 /* drawing ops follow */
145 };
146
147 /*
148 * A repair request.
149 */
150 struct pkt_rreq {
151 nd_uint32_t pr_id; /* source id of drawops to be repaired */
152 struct PageID pr_page; /* page of drawops */
153 nd_uint32_t pr_sseq; /* start seqno */
154 nd_uint32_t pr_eseq; /* end seqno */
155 };
156
157 /*
158 * A repair reply.
159 */
160 struct pkt_rrep {
161 nd_uint32_t pr_id; /* original site id of ops */
162 struct pkt_dop pr_dop;
163 /* drawing ops follow */
164 };
165
166 struct id_off {
167 nd_uint32_t id;
168 nd_uint32_t off;
169 };
170
171 struct pgstate {
172 nd_uint32_t slot;
173 struct PageID page;
174 nd_uint16_t nid;
175 nd_uint16_t rsvd;
176 /* seqptr's */
177 };
178
179 /*
180 * An announcement packet.
181 */
182 struct pkt_id {
183 nd_uint32_t pi_mslot;
184 struct PageID pi_mpage; /* current page */
185 struct pgstate pi_ps;
186 /* seqptr's */
187 /* null-terminated site name */
188 };
189
190 struct pkt_preq {
191 struct PageID pp_page;
192 nd_uint32_t pp_low;
193 nd_uint32_t pp_high;
194 };
195
196 struct pkt_prep {
197 nd_uint32_t pp_n; /* size of pageid array */
198 /* pgstate's follow */
199 };
200
201 static int
202 wb_id(netdissect_options *ndo,
203 const struct pkt_id *id, u_int len)
204 {
205 u_int i;
206 const u_char *sitename;
207 const struct id_off *io;
208 char c;
209 u_int nid;
210
211 ND_PRINT(" wb-id:");
212 if (len < sizeof(*id))
213 return (-1);
214 len -= sizeof(*id);
215
216 ND_PRINT(" %u/%s:%u (max %u/%s:%u) ",
217 GET_BE_U_4(id->pi_ps.slot),
218 GET_IPADDR_STRING(id->pi_ps.page.p_sid),
219 GET_BE_U_4(id->pi_ps.page.p_uid),
220 GET_BE_U_4(id->pi_mslot),
221 GET_IPADDR_STRING(id->pi_mpage.p_sid),
222 GET_BE_U_4(id->pi_mpage.p_uid));
223 /* now the rest of the fixed-size part of struct pkt_id */
224 ND_TCHECK_SIZE(id);
225
226 nid = GET_BE_U_2(id->pi_ps.nid);
227 if (len < sizeof(*io) * nid)
228 return (-1);
229 len -= sizeof(*io) * nid;
230 io = (const struct id_off *)(id + 1);
231 sitename = (const u_char *)(io + nid);
232
233 c = '<';
234 for (i = 0; i < nid; ++io, ++i) {
235 ND_PRINT("%c%s:%u",
236 c, GET_IPADDR_STRING(io->id), GET_BE_U_4(io->off));
237 c = ',';
238 }
239 ND_PRINT("> \"");
240 nd_printjnp(ndo, sitename, len);
241 ND_PRINT("\"");
242 return (0);
243 }
244
245 static int
246 wb_rreq(netdissect_options *ndo,
247 const struct pkt_rreq *rreq, u_int len)
248 {
249 ND_PRINT(" wb-rreq:");
250 if (len < sizeof(*rreq))
251 return (-1);
252
253 ND_PRINT(" please repair %s %s:%u<%u:%u>",
254 GET_IPADDR_STRING(rreq->pr_id),
255 GET_IPADDR_STRING(rreq->pr_page.p_sid),
256 GET_BE_U_4(rreq->pr_page.p_uid),
257 GET_BE_U_4(rreq->pr_sseq),
258 GET_BE_U_4(rreq->pr_eseq));
259 return (0);
260 }
261
262 static int
263 wb_preq(netdissect_options *ndo,
264 const struct pkt_preq *preq, u_int len)
265 {
266 ND_PRINT(" wb-preq:");
267 if (len < sizeof(*preq))
268 return (-1);
269
270 ND_PRINT(" need %u/%s:%u",
271 GET_BE_U_4(preq->pp_low),
272 GET_IPADDR_STRING(preq->pp_page.p_sid),
273 GET_BE_U_4(preq->pp_page.p_uid));
274 /* now the rest of the fixed-size part of struct pkt_req */
275 ND_TCHECK_SIZE(preq);
276 return (0);
277 }
278
279 static int
280 wb_prep(netdissect_options *ndo,
281 const struct pkt_prep *prep, u_int len)
282 {
283 u_int n;
284 const struct pgstate *ps;
285
286 ND_PRINT(" wb-prep:");
287 if (len < sizeof(*prep))
288 return (-1);
289 n = GET_BE_U_4(prep->pp_n);
290 ps = (const struct pgstate *)(prep + 1);
291 while (n != 0) {
292 const struct id_off *io, *ie;
293 char c = '<';
294
295 ND_PRINT(" %u/%s:%u",
296 GET_BE_U_4(ps->slot),
297 GET_IPADDR_STRING(ps->page.p_sid),
298 GET_BE_U_4(ps->page.p_uid));
299 /* now the rest of the fixed-size part of struct pgstate */
300 ND_TCHECK_SIZE(ps);
301 io = (const struct id_off *)(ps + 1);
302 for (ie = io + GET_U_1(ps->nid); io < ie; ++io) {
303 ND_PRINT("%c%s:%u", c, GET_IPADDR_STRING(io->id),
304 GET_BE_U_4(io->off));
305 c = ',';
306 }
307 ND_PRINT(">");
308 ps = (const struct pgstate *)io;
309 n--;
310 }
311 return 0;
312 }
313
314 static void
315 wb_dops(netdissect_options *ndo, const struct pkt_dop *dop,
316 uint32_t ss, uint32_t es)
317 {
318 const struct dophdr *dh = (const struct dophdr *)((const u_char *)dop + sizeof(*dop));
319
320 ND_PRINT(" <");
321 for ( ; ss <= es; ++ss) {
322 u_int t;
323
324 t = GET_U_1(dh->dh_type);
325
326 ND_PRINT(" %s", tok2str(dop_str, "dop-%u!", t));
327 if (t == DT_SKIP || t == DT_HOLE) {
328 uint32_t ts = GET_BE_U_4(dh->dh_ts);
329 ND_PRINT("%u", ts - ss + 1);
330 if (ss > ts || ts > es) {
331 ND_PRINT("[|]");
332 if (ts < ss)
333 return;
334 }
335 ss = ts;
336 }
337 dh = DOP_NEXT(dh);
338 }
339 ND_PRINT(" >");
340 }
341
342 static int
343 wb_rrep(netdissect_options *ndo,
344 const struct pkt_rrep *rrep, u_int len)
345 {
346 const struct pkt_dop *dop = &rrep->pr_dop;
347
348 ND_PRINT(" wb-rrep:");
349 if (len < sizeof(*rrep))
350 return (-1);
351 len -= sizeof(*rrep);
352
353 ND_PRINT(" for %s %s:%u<%u:%u>",
354 GET_IPADDR_STRING(rrep->pr_id),
355 GET_IPADDR_STRING(dop->pd_page.p_sid),
356 GET_BE_U_4(dop->pd_page.p_uid),
357 GET_BE_U_4(dop->pd_sseq),
358 GET_BE_U_4(dop->pd_eseq));
359
360 if (ndo->ndo_vflag)
361 wb_dops(ndo, dop,
362 GET_BE_U_4(dop->pd_sseq),
363 GET_BE_U_4(dop->pd_eseq));
364 return (0);
365 }
366
367 static int
368 wb_drawop(netdissect_options *ndo,
369 const struct pkt_dop *dop, u_int len)
370 {
371 ND_PRINT(" wb-dop:");
372 if (len < sizeof(*dop))
373 return (-1);
374 len -= sizeof(*dop);
375
376 ND_PRINT(" %s:%u<%u:%u>",
377 GET_IPADDR_STRING(dop->pd_page.p_sid),
378 GET_BE_U_4(dop->pd_page.p_uid),
379 GET_BE_U_4(dop->pd_sseq),
380 GET_BE_U_4(dop->pd_eseq));
381
382 if (ndo->ndo_vflag)
383 wb_dops(ndo, dop,
384 GET_BE_U_4(dop->pd_sseq),
385 GET_BE_U_4(dop->pd_eseq));
386 return (0);
387 }
388
389 /*
390 * Print whiteboard multicast packets.
391 */
392 UNALIGNED_OK
393 void
394 wb_print(netdissect_options *ndo,
395 const u_char *hdr, u_int len)
396 {
397 const struct pkt_hdr *ph;
398 uint8_t type;
399 int print_result;
400
401 ndo->ndo_protocol = "wb";
402 ph = (const struct pkt_hdr *)hdr;
403 if (len < sizeof(*ph))
404 goto invalid;
405 ND_TCHECK_SIZE(ph);
406 len -= sizeof(*ph);
407
408 if (GET_U_1(ph->ph_flags))
409 ND_PRINT("*");
410 type = GET_U_1(ph->ph_type);
411 switch (type) {
412
413 case PT_KILL:
414 ND_PRINT(" wb-kill");
415 return;
416
417 case PT_ID:
418 print_result = wb_id(ndo, (const struct pkt_id *)(ph + 1), len);
419 break;
420
421 case PT_RREQ:
422 print_result = wb_rreq(ndo, (const struct pkt_rreq *)(ph + 1), len);
423 break;
424
425 case PT_RREP:
426 print_result = wb_rrep(ndo, (const struct pkt_rrep *)(ph + 1), len);
427 break;
428
429 case PT_DRAWOP:
430 print_result = wb_drawop(ndo, (const struct pkt_dop *)(ph + 1), len);
431 break;
432
433 case PT_PREQ:
434 print_result = wb_preq(ndo, (const struct pkt_preq *)(ph + 1), len);
435 break;
436
437 case PT_PREP:
438 print_result = wb_prep(ndo, (const struct pkt_prep *)(ph + 1), len);
439 break;
440
441 default:
442 ND_PRINT(" wb-%u!", type);
443 print_result = -1;
444 }
445 if (print_result < 0)
446 goto invalid;
447 return;
448
449 invalid:
450 nd_print_invalid(ndo);
451 }
452