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