text: /*
   * Copyright (c) 1993, 1994, 1995, 1996
   *	The Regents of the University of California.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that: (1) source code distributions
   * retain the above copyright notice and this paragraph in its entirety, (2)
   * distributions including binary code include the above copyright notice and
   * this paragraph in its entirety in the documentation or other materials
   * provided with the distribution, and (3) all advertising materials mentioning
   * features or use of this software display the following acknowledgement:
   * ``This product includes software developed by the University of California,
   * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
   * the University nor the names of its contributors may be used to endorse
   * or promote products derived from this software without specific prior
   * written permission.
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
   * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   */
  
  #ifndef lint
  static const char rcsid[] _U_ =
      "@(#) $Header$ (LBL)";
  #endif
  
  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
  
  #include <tcpdump-stdinc.h>
  
  #include <stdio.h>
  
  #include "interface.h"
  #include "addrtoname.h"
  #include "extract.h"
  
  /* XXX need to add byte-swapping macros! */
  /* XXX - you mean like the ones in "extract.h"? */
  
  /*
   * Largest packet size.  Everything should fit within this space.
   * For instance, multiline objects are sent piecewise.
   */
  #define MAXFRAMESIZE 1024
  
  /*
   * Multiple drawing ops can be sent in one packet.  Each one starts on a
   * an even multiple of DOP_ALIGN bytes, which must be a power of two.
   */
  #define DOP_ALIGN 4
  #define DOP_ROUNDUP(x)	((((int)(x)) + (DOP_ALIGN - 1)) & ~(DOP_ALIGN - 1))
  #define DOP_NEXT(d)\
  	((struct dophdr *)((u_char *)(d) + \
  			  DOP_ROUNDUP(EXTRACT_16BITS(&(d)->dh_len) + sizeof(*(d)))))
  
  /*
   * Format of the whiteboard packet header.
   * The transport level header.
   */
  struct pkt_hdr {
  	u_int32_t ph_src;		/* site id of source */
  	u_int32_t ph_ts;		/* time stamp (for skew computation) */
  	u_int16_t ph_version;	/* version number */
  	u_char ph_type;		/* message type */
  	u_char ph_flags;	/* message flags */
  };
  
  /* Packet types */
  #define PT_DRAWOP	0	/* drawing operation */
  #define PT_ID		1	/* announcement packet */
  #define PT_RREQ		2	/* repair request */
  #define PT_RREP		3	/* repair reply */
  #define PT_KILL		4	/* terminate participation */
  #define PT_PREQ         5       /* page vector request */
  #define PT_PREP         7       /* page vector reply */
  
  #ifdef PF_USER
  #undef PF_USER			/* {Digital,Tru64} UNIX define this, alas */
  #endif
  
  /* flags */
  #define PF_USER		0x01	/* hint that packet has interactive data */
  #define PF_VIS		0x02	/* only visible ops wanted */
  
  struct PageID {
  	u_int32_t p_sid;		/* session id of initiator */
  	u_int32_t p_uid;		/* page number */
  };
  
  struct dophdr {
  	u_int32_t  dh_ts;		/* sender's timestamp */
  	u_int16_t	dh_len;		/* body length */
  	u_char	dh_flags;
  	u_char	dh_type;	/* body type */
  	/* body follows */
  };
  /*
   * Drawing op sub-types.
   */
  #define DT_RECT         2
  #define DT_LINE         3
  #define DT_ML           4
  #define DT_DEL          5
  #define DT_XFORM        6
  #define DT_ELL          7
  #define DT_CHAR         8
  #define DT_STR          9
  #define DT_NOP          10
  #define DT_PSCODE       11
  #define DT_PSCOMP       12
  #define DT_REF          13
  #define DT_SKIP         14
  #define DT_HOLE         15
  #define DT_MAXTYPE      15
  
  /*
   * A drawing operation.
   */
  struct pkt_dop {
  	struct PageID pd_page;	/* page that operations apply to */
  	u_int32_t	pd_sseq;	/* start sequence number */
  	u_int32_t	pd_eseq;	/* end sequence number */
  	/* drawing ops follow */
  };
  
  /*
   * A repair request.
   */
  struct pkt_rreq {
          u_int32_t pr_id;           /* source id of drawops to be repaired */
          struct PageID pr_page;           /* page of drawops */
          u_int32_t pr_sseq;         /* start seqno */
          u_int32_t pr_eseq;         /* end seqno */
  };
  
  /*
   * A repair reply.
   */
  struct pkt_rrep {
  	u_int32_t pr_id;	/* original site id of ops  */
  	struct pkt_dop pr_dop;
  	/* drawing ops follow */
  };
  
  struct id_off {
          u_int32_t id;
          u_int32_t off;
  };
  
  struct pgstate {
  	u_int32_t slot;
  	struct PageID page;
  	u_int16_t nid;
  	u_int16_t rsvd;
          /* seqptr's */
  };
  
  /*
   * An announcement packet.
   */
  struct pkt_id {
  	u_int32_t pi_mslot;
          struct PageID    pi_mpage;        /* current page */
  	struct pgstate pi_ps;
          /* seqptr's */
          /* null-terminated site name */
  };
  
  struct pkt_preq {
          struct PageID  pp_page;
          u_int32_t  pp_low;
          u_int32_t  pp_high;
  };
  
  struct pkt_prep {
          u_int32_t  pp_n;           /* size of pageid array */
          /* pgstate's follow */
  };
  
  static int
  wb_id(const struct pkt_id *id, u_int len)
  {
  	int i;
  	const char *cp;
  	const struct id_off *io;
  	char c;
  	int nid;
  
  	printf(" wb-id:");
  	if (len < sizeof(*id) || (u_char *)(id + 1) > snapend)
  		return (-1);
  	len -= sizeof(*id);
  
  	printf(" %u/%s:%u (max %u/%s:%u) ",
  	       EXTRACT_32BITS(&id->pi_ps.slot),
  	       ipaddr_string(&id->pi_ps.page.p_sid),
  	       EXTRACT_32BITS(&id->pi_ps.page.p_uid),
  	       EXTRACT_32BITS(&id->pi_mslot),
  	       ipaddr_string(&id->pi_mpage.p_sid),
  	       EXTRACT_32BITS(&id->pi_mpage.p_uid));
  
  	nid = EXTRACT_16BITS(&id->pi_ps.nid);
  	len -= sizeof(*io) * nid;
  	io = (struct id_off *)(id + 1);
  	cp = (char *)(io + nid);
  	if ((u_char *)cp + len <= snapend) {
  		putchar('"');
  		(void)fn_print((u_char *)cp, (u_char *)cp + len);
  		putchar('"');
  	}
  
  	c = '<';
  	for (i = 0; i < nid && (u_char *)(io + 1) <= snapend; ++io, ++i) {
  		printf("%c%s:%u",
  		    c, ipaddr_string(&io->id), EXTRACT_32BITS(&io->off));
  		c = ',';
  	}
  	if (i >= nid) {
  		printf(">");
  		return (0);
  	}
  	return (-1);
  }
  
  static int
  wb_rreq(const struct pkt_rreq *rreq, u_int len)
  {
  	printf(" wb-rreq:");
  	if (len < sizeof(*rreq) || (u_char *)(rreq + 1) > snapend)
  		return (-1);
  
  	printf(" please repair %s %s:%u<%u:%u>",
  	       ipaddr_string(&rreq->pr_id),
  	       ipaddr_string(&rreq->pr_page.p_sid),
  	       EXTRACT_32BITS(&rreq->pr_page.p_uid),
  	       EXTRACT_32BITS(&rreq->pr_sseq),
  	       EXTRACT_32BITS(&rreq->pr_eseq));
  	return (0);
  }
  
  static int
  wb_preq(const struct pkt_preq *preq, u_int len)
  {
  	printf(" wb-preq:");
  	if (len < sizeof(*preq) || (u_char *)(preq + 1) > snapend)
  		return (-1);
  
  	printf(" need %u/%s:%u",
  	       EXTRACT_32BITS(&preq->pp_low),
  	       ipaddr_string(&preq->pp_page.p_sid),
  	       EXTRACT_32BITS(&preq->pp_page.p_uid));
  	return (0);
  }
  
  static int
  wb_prep(const struct pkt_prep *prep, u_int len)
  {
  	int n;
  	const struct pgstate *ps;
  	const u_char *ep = snapend;
  
  	printf(" wb-prep:");
  	if (len < sizeof(*prep)) {
  		return (-1);
  	}
  	n = EXTRACT_32BITS(&prep->pp_n);
  	ps = (const struct pgstate *)(prep + 1);
  	while (--n >= 0 && (u_char *)(ps + 1) <= ep) {
  		const struct id_off *io, *ie;
  		char c = '<';
  
  		printf(" %u/%s:%u",
  		    EXTRACT_32BITS(&ps->slot),
  		    ipaddr_string(&ps->page.p_sid),
  		    EXTRACT_32BITS(&ps->page.p_uid));
  		io = (struct id_off *)(ps + 1);
  		for (ie = io + ps->nid; io < ie && (u_char *)(io + 1) <= ep; ++io) {
  			printf("%c%s:%u", c, ipaddr_string(&io->id),
  			    EXTRACT_32BITS(&io->off));
  			c = ',';
  		}
  		printf(">");
  		ps = (struct pgstate *)io;
  	}
  	return ((u_char *)ps <= ep? 0 : -1);
  }
  
  
  const char *dopstr[] = {
  	"dop-0!",
  	"dop-1!",
  	"RECT",
  	"LINE",
  	"ML",
  	"DEL",
  	"XFORM",
  	"ELL",
  	"CHAR",
  	"STR",
  	"NOP",
  	"PSCODE",
  	"PSCOMP",
  	"REF",
  	"SKIP",
  	"HOLE",
  };
  
  static int
  wb_dops(const struct dophdr *dh, u_int32_t ss, u_int32_t es)
  {
  	printf(" <");
  	for ( ; ss <= es; ++ss) {
  		register int t = dh->dh_type;
  
  		if (t > DT_MAXTYPE)
  			printf(" dop-%d!", t);
  		else {
  			printf(" %s", dopstr[t]);
  			if (t == DT_SKIP || t == DT_HOLE) {
  				u_int32_t ts = EXTRACT_32BITS(&dh->dh_ts);
  				printf("%d", ts - ss + 1);
  				if (ss > ts || ts > es) {
  					printf("[|]");
  					if (ts < ss)
  						return (0);
  				}
  				ss = ts;
  			}
  		}
  		dh = DOP_NEXT(dh);
  		if ((u_char *)dh > snapend) {
  			printf("[|wb]");
  			break;
  		}
  	}
  	printf(" >");
  	return (0);
  }
  
  static int
  wb_rrep(const struct pkt_rrep *rrep, u_int len)
  {
  	const struct pkt_dop *dop = &rrep->pr_dop;
  
  	printf(" wb-rrep:");
  	if (len < sizeof(*rrep) || (u_char *)(rrep + 1) > snapend)
  		return (-1);
  	len -= sizeof(*rrep);
  
  	printf(" for %s %s:%u<%u:%u>",
  	    ipaddr_string(&rrep->pr_id),
  	    ipaddr_string(&dop->pd_page.p_sid),
  	    EXTRACT_32BITS(&dop->pd_page.p_uid),
  	    EXTRACT_32BITS(&dop->pd_sseq),
  	    EXTRACT_32BITS(&dop->pd_eseq));
  
  	if (vflag)
  		return (wb_dops((const struct dophdr *)(dop + 1),
  		    EXTRACT_32BITS(&dop->pd_sseq),
  		    EXTRACT_32BITS(&dop->pd_eseq)));
  	return (0);
  }
  
  static int
  wb_drawop(const struct pkt_dop *dop, u_int len)
  {
  	printf(" wb-dop:");
  	if (len < sizeof(*dop) || (u_char *)(dop + 1) > snapend)
  		return (-1);
  	len -= sizeof(*dop);
  
  	printf(" %s:%u<%u:%u>",
  	    ipaddr_string(&dop->pd_page.p_sid),
  	    EXTRACT_32BITS(&dop->pd_page.p_uid),
  	    EXTRACT_32BITS(&dop->pd_sseq),
  	    EXTRACT_32BITS(&dop->pd_eseq));
  
  	if (vflag)
  		return (wb_dops((const struct dophdr *)(dop + 1),
  				EXTRACT_32BITS(&dop->pd_sseq),
  				EXTRACT_32BITS(&dop->pd_eseq)));
  	return (0);
  }
  
  /*
   * Print whiteboard multicast packets.
   */
  void
  wb_print(register const void *hdr, register u_int len)
  {
  	register const struct pkt_hdr *ph;
  
  	ph = (const struct pkt_hdr *)hdr;
  	if (len < sizeof(*ph) || (u_char *)(ph + 1) > snapend) {
  		printf("[|wb]");
  		return;
  	}
  	len -= sizeof(*ph);
  
  	if (ph->ph_flags)
  		printf("*");
  	switch (ph->ph_type) {
  
  	case PT_KILL:
  		printf(" wb-kill");
  		return;
  
  	case PT_ID:
  		if (wb_id((struct pkt_id *)(ph + 1), len) >= 0)
  			return;
  		break;
  
  	case PT_RREQ:
  		if (wb_rreq((struct pkt_rreq *)(ph + 1), len) >= 0)
  			return;
  		break;
  
  	case PT_RREP:
  		if (wb_rrep((struct pkt_rrep *)(ph + 1), len) >= 0)
  			return;
  		break;
  
  	case PT_DRAWOP:
  		if (wb_drawop((struct pkt_dop *)(ph + 1), len) >= 0)
  			return;
  		break;
  
  	case PT_PREQ:
  		if (wb_preq((struct pkt_preq *)(ph + 1), len) >= 0)
  			return;
  		break;
  
  	case PT_PREP:
  		if (wb_prep((struct pkt_prep *)(ph + 1), len) >= 0)
  			return;
  		break;
  
  	default:
  		printf(" wb-%d!", ph->ph_type);
  		return;
  	}
  }
  