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