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