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 */ 58 struct 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 85 struct PageID { 86 nd_uint32_t p_sid; /* session id of initiator */ 87 nd_uint32_t p_uid; /* page number */ 88 }; 89 90 struct 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 114 static 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 */ 135 struct 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 */ 145 struct 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 */ 155 struct 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 161 struct id_off { 162 nd_uint32_t id; 163 nd_uint32_t off; 164 }; 165 166 struct 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 */ 177 struct 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 185 struct pkt_preq { 186 struct PageID pp_page; 187 nd_uint32_t pp_low; 188 nd_uint32_t pp_high; 189 }; 190 191 struct pkt_prep { 192 nd_uint32_t pp_n; /* size of pageid array */ 193 /* pgstate's follow */ 194 }; 195 196 static int 197 wb_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 240 static int 241 wb_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 257 static int 258 wb_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 274 static int 275 wb_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 309 static void 310 wb_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 337 static int 338 wb_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 362 static int 363 wb_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 */ 387 void 388 wb_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 443 invalid: 444 nd_print_invalid(ndo); 445 } 446