Home | History | Annotate | Line # | Download | only in dist
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