Beispiel #1
0
static void
print_attr_string(netdissect_options *ndo,
                  const u_char *data, u_int length, u_short attr_code)
{
   u_int i;

   ND_TCHECK_LEN(data, length);

   switch(attr_code)
   {
      case TUNNEL_PASS:
           if (length < 3)
              goto trunc;
           if (EXTRACT_U_1(data) && (EXTRACT_U_1(data) <= 0x1F))
              ND_PRINT("Tag[%u] ", EXTRACT_U_1(data));
           else
              ND_PRINT("Tag[Unused] ");
           data++;
           length--;
           ND_PRINT("Salt %u ", EXTRACT_BE_U_2(data));
           data+=2;
           length-=2;
        break;
      case TUNNEL_CLIENT_END:
      case TUNNEL_SERVER_END:
      case TUNNEL_PRIV_GROUP:
      case TUNNEL_ASSIGN_ID:
      case TUNNEL_CLIENT_AUTH:
      case TUNNEL_SERVER_AUTH:
           if (EXTRACT_U_1(data) <= 0x1F)
           {
              if (length < 1)
                 goto trunc;
              if (EXTRACT_U_1(data))
                ND_PRINT("Tag[%u] ", EXTRACT_U_1(data));
              else
                ND_PRINT("Tag[Unused] ");
              data++;
              length--;
           }
        break;
      case EGRESS_VLAN_NAME:
           if (length < 1)
              goto trunc;
           ND_PRINT("%s (0x%02x) ",
                  tok2str(rfc4675_tagged,"Unknown tag",EXTRACT_U_1(data)),
                  EXTRACT_U_1(data));
           data++;
           length--;
        break;
   }

   for (i=0; i < length && EXTRACT_U_1(data); i++, data++)
       ND_PRINT("%c", ND_ISPRINT(EXTRACT_U_1(data)) ? EXTRACT_U_1(data) : '.');

   return;

   trunc:
      nd_print_trunc(ndo);
}
Beispiel #2
0
static void
cmu_print(netdissect_options *ndo,
	  const u_char *bp)
{
	const struct cmu_vend *cmu;
	uint8_t v_flags;

	ND_PRINT(" vend-cmu");
	cmu = (const struct cmu_vend *)bp;

	/* Only print if there are unknown bits */
	ND_TCHECK_4(cmu->v_flags);
	v_flags = EXTRACT_U_1(cmu->v_flags);
	if ((v_flags & ~(VF_SMASK)) != 0)
		ND_PRINT(" F:0x%x", v_flags);
	PRINTCMUADDR(v_dgate, "DG");
	PRINTCMUADDR(v_smask, v_flags & VF_SMASK ? "SM" : "SM*");
	PRINTCMUADDR(v_dns1, "NS1");
	PRINTCMUADDR(v_dns2, "NS2");
	PRINTCMUADDR(v_ins1, "IEN1");
	PRINTCMUADDR(v_ins2, "IEN2");
	PRINTCMUADDR(v_ts1, "TS1");
	PRINTCMUADDR(v_ts2, "TS2");
	return;

trunc:
	nd_print_trunc(ndo);
}
Beispiel #3
0
static int
ahcp_time_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
{
	time_t t;
	struct tm *tm;
	char buf[BUFSIZE];

	if (cp + 4 != ep)
		goto invalid;
	ND_TCHECK_4(cp);
	t = EXTRACT_BE_U_4(cp);
	if (NULL == (tm = gmtime(&t)))
		ND_PRINT(": gmtime() error");
	else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
		ND_PRINT(": strftime() error");
	else
		ND_PRINT(": %s UTC", buf);
	return 0;

invalid:
	ND_PRINT("%s", istr);
	ND_TCHECK_LEN(cp, ep - cp);
	return 0;
trunc:
	nd_print_trunc(ndo);
	return -1;
}
Beispiel #4
0
void
gre_print(netdissect_options *ndo, const u_char *bp, u_int length)
{
	u_int len = length, vers;

	ndo->ndo_protocol = "gre";
	ND_TCHECK_2(bp);
	if (len < 2)
		goto trunc;
	vers = EXTRACT_BE_U_2(bp) & GRE_VERS_MASK;
        ND_PRINT("GREv%u",vers);

        switch(vers) {
        case 0:
            gre_print_0(ndo, bp, len);
            break;
        case 1:
            gre_print_1(ndo, bp, len);
            break;
	default:
            ND_PRINT(" ERROR: unknown-version");
            break;
        }
        return;

trunc:
	nd_print_trunc(ndo);
	return;
}
Beispiel #5
0
void
vxlan_print(netdissect_options *ndo, const u_char *bp, u_int len)
{
    uint8_t flags;
    uint32_t vni;

    ndo->ndo_protocol = "vxlan";
    if (len < VXLAN_HDR_LEN)
        goto trunc;

    ND_TCHECK_LEN(bp, VXLAN_HDR_LEN);

    flags = EXTRACT_U_1(bp);
    bp += 4;

    vni = EXTRACT_BE_U_3(bp);
    bp += 4;

    ND_PRINT("VXLAN, ");
    ND_PRINT("flags [%s] (0x%02x), ", flags & 0x08 ? "I" : ".", flags);
    ND_PRINT("vni %u\n", vni);

    ether_print(ndo, bp, len - VXLAN_HDR_LEN, ndo->ndo_snapend - bp, NULL, NULL);

    return;

trunc:
    nd_print_trunc(ndo);
}
Beispiel #6
0
void
nfsreply_print(netdissect_options *ndo,
               const u_char *bp, u_int length,
               const u_char *bp2)
{
	const struct sunrpc_msg *rp;
	char srcid[20], dstid[20];	/*fits 32bit*/

	ndo->ndo_protocol = "nfs";
	nfserr = 0;		/* assume no error */
	rp = (const struct sunrpc_msg *)bp;

	ND_TCHECK_4(rp->rm_xid);
	if (!ndo->ndo_nflag) {
		strlcpy(srcid, "nfs", sizeof(srcid));
		nd_snprintf(dstid, sizeof(dstid), "%u",
		    EXTRACT_BE_U_4(rp->rm_xid));
	} else {
		nd_snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
		nd_snprintf(dstid, sizeof(dstid), "%u",
		    EXTRACT_BE_U_4(rp->rm_xid));
	}
	print_nfsaddr(ndo, bp2, srcid, dstid);

	nfsreply_noaddr_print(ndo, bp, length, bp2);
	return;

trunc:
	if (!nfserr)
		nd_print_trunc(ndo);
}
Beispiel #7
0
/*
 * This is the top level routine of the printer.  'p' points
 * to the bluetooth header of the packet, 'h->ts' is the timestamp,
 * 'h->len' is the length of the packet off the wire, and 'h->caplen'
 * is the number of bytes actually captured.
 */
u_int
bt_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
{
	u_int length = h->len;
	u_int caplen = h->caplen;
	const bluetooth_h4_header* hdr = (const bluetooth_h4_header*)p;

	ndo->ndo_protocol = "bt_if";
	if (caplen < BT_HDRLEN || length < BT_HDRLEN)
		goto trunc;
	caplen -= BT_HDRLEN;
	length -= BT_HDRLEN;
	p += BT_HDRLEN;
	ND_TCHECK_4(&hdr->direction);
	if (ndo->ndo_eflag)
		ND_PRINT("hci length %u, direction %s, ", length,
			 (EXTRACT_BE_U_4(hdr->direction)&0x1) ? "in" : "out");

	if (!ndo->ndo_suppress_default_print)
		ND_DEFAULTPRINT(p, caplen);
	return (BT_HDRLEN);

trunc:
	nd_print_trunc(ndo);
	return (BT_HDRLEN);
}
Beispiel #8
0
static void
print_attr_time(netdissect_options *ndo,
                const u_char *data, u_int length, u_short attr_code _U_)
{
   time_t attr_time;
   char string[26];

   if (length != 4)
   {
       ND_PRINT("ERROR: length %u != 4", length);
       return;
   }

   ND_TCHECK_4(data);

   attr_time = EXTRACT_BE_U_4(data);
   strlcpy(string, ctime(&attr_time), sizeof(string));
   /* Get rid of the newline */
   string[24] = '\0';
   ND_PRINT("%.24s", string);
   return;

   trunc:
     nd_print_trunc(ndo);
}
Beispiel #9
0
static void
print_attr_netmask6(netdissect_options *ndo,
                    const u_char *data, u_int length, u_short attr_code _U_)
{
   u_char data2[16];

   if (length < 2 || length > 18)
   {
       ND_PRINT("ERROR: length %u not in range (2..18)", length);
       return;
   }
   ND_TCHECK_LEN(data, length);
   if (EXTRACT_U_1(data + 1) > 128)
   {
      ND_PRINT("ERROR: netmask %u not in range (0..128)", EXTRACT_U_1(data + 1));
      return;
   }

   memset(data2, 0, sizeof(data2));
   if (length > 2)
      memcpy(data2, data+2, length-2);

   ND_PRINT("%s/%u", ip6addr_string(ndo, data2), EXTRACT_U_1(data + 1));

   if (EXTRACT_U_1(data + 1) > 8 * (length - 2))
      ND_PRINT(" (inconsistent prefix length)");

   return;

   trunc:
     nd_print_trunc(ndo);
}
Beispiel #10
0
static void
print_attr_address(netdissect_options *ndo,
                   const u_char *data, u_int length, u_short attr_code)
{
   if (length != 4)
   {
       ND_PRINT("ERROR: length %u != 4", length);
       return;
   }

   ND_TCHECK_4(data);

   switch(attr_code)
   {
      case FRM_IPADDR:
      case LOG_IPHOST:
           if (EXTRACT_BE_U_4(data) == 0xFFFFFFFF )
              ND_PRINT("User Selected");
           else
              if (EXTRACT_BE_U_4(data) == 0xFFFFFFFE )
                 ND_PRINT("NAS Select");
              else
                 ND_PRINT("%s",ipaddr_string(ndo, data));
      break;

      default:
          ND_PRINT("%s", ipaddr_string(ndo, data));
      break;
   }

   return;

   trunc:
     nd_print_trunc(ndo);
}
Beispiel #11
0
void
radius_print(netdissect_options *ndo,
             const u_char *dat, u_int length)
{
   const struct radius_hdr *rad;
   u_int len, auth_idx;

   ndo->ndo_protocol = "radius";
   ND_TCHECK_LEN(dat, MIN_RADIUS_LEN);
   rad = (const struct radius_hdr *)dat;
   len = EXTRACT_BE_U_2(rad->len);

   if (len < MIN_RADIUS_LEN)
   {
	  nd_print_trunc(ndo);
	  return;
   }

   if (len > length)
	  len = length;

   if (ndo->ndo_vflag < 1) {
       ND_PRINT("RADIUS, %s (%u), id: 0x%02x length: %u",
              tok2str(radius_command_values,"Unknown Command",EXTRACT_U_1(rad->code)),
              EXTRACT_U_1(rad->code),
              EXTRACT_U_1(rad->id),
              len);
       return;
   }
   else {
       ND_PRINT("RADIUS, length: %u\n\t%s (%u), id: 0x%02x, Authenticator: ",
              len,
              tok2str(radius_command_values,"Unknown Command",EXTRACT_U_1(rad->code)),
              EXTRACT_U_1(rad->code),
              EXTRACT_U_1(rad->id));

       for(auth_idx=0; auth_idx < 16; auth_idx++)
            ND_PRINT("%02x", rad->auth[auth_idx]);
   }

   if (len > MIN_RADIUS_LEN)
      radius_attrs_print(ndo, dat + MIN_RADIUS_LEN, len - MIN_RADIUS_LEN);
   return;

trunc:
   nd_print_trunc(ndo);
}
Beispiel #12
0
/*
 * Print RRCP requests
 */
void
rrcp_print(netdissect_options *ndo,
	  const u_char *cp,
	  u_int length _U_,
	  const struct lladdr_info *src,
	  const struct lladdr_info *dst)
{
	uint8_t rrcp_proto;
	uint8_t rrcp_opcode;

	ndo->ndo_protocol = "rrcp";
	ND_TCHECK_1(cp + RRCP_PROTO_OFFSET);
	rrcp_proto = EXTRACT_U_1(cp + RRCP_PROTO_OFFSET);
	ND_TCHECK_1(cp + RRCP_OPCODE_ISREPLY_OFFSET);
	rrcp_opcode = EXTRACT_U_1((cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_OPCODE_MASK;
	if (src != NULL && dst != NULL) {
		ND_PRINT("%s > %s, ",
			(src->addr_string)(ndo, src->addr),
			(dst->addr_string)(ndo, dst->addr));
	}
	ND_PRINT("%s %s",
		tok2str(proto_values,"RRCP-0x%02x",rrcp_proto),
		((EXTRACT_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY) ? "reply" : "query");
	if (rrcp_proto==1){
    	    ND_PRINT(": %s",
		     tok2str(opcode_values,"unknown opcode (0x%02x)",rrcp_opcode));
	}
	if (rrcp_opcode==1 || rrcp_opcode==2){
	    ND_TCHECK_6(cp + RRCP_REG_ADDR_OFFSET);
    	    ND_PRINT(" addr=0x%04x, data=0x%08x",
		     EXTRACT_LE_U_2(cp + RRCP_REG_ADDR_OFFSET),
		     EXTRACT_LE_U_4(cp + RRCP_REG_DATA_OFFSET));
	}
	if (rrcp_proto==1){
	    ND_TCHECK_2(cp + RRCP_AUTHKEY_OFFSET);
    	    ND_PRINT(", auth=0x%04x",
		  EXTRACT_BE_U_2(cp + RRCP_AUTHKEY_OFFSET));
	}
	if (rrcp_proto==1 && rrcp_opcode==0 &&
	     ((EXTRACT_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY)){
	    ND_TCHECK_4(cp + RRCP_VENDOR_ID_OFFSET);
	    ND_PRINT(" downlink_port=%u, uplink_port=%u, uplink_mac=%s, vendor_id=%08x ,chip_id=%04x ",
		     EXTRACT_U_1(cp + RRCP_DOWNLINK_PORT_OFFSET),
		     EXTRACT_U_1(cp + RRCP_UPLINK_PORT_OFFSET),
		     etheraddr_string(ndo, cp + RRCP_UPLINK_MAC_OFFSET),
		     EXTRACT_BE_U_4(cp + RRCP_VENDOR_ID_OFFSET),
		     EXTRACT_BE_U_2(cp + RRCP_CHIP_ID_OFFSET));
	}else if (rrcp_opcode==1 || rrcp_opcode==2 || rrcp_proto==2){
	    ND_TCHECK_4(cp + RRCP_COOKIE2_OFFSET);
	    ND_PRINT(", cookie=0x%08x%08x ",
		    EXTRACT_BE_U_4(cp + RRCP_COOKIE2_OFFSET),
		    EXTRACT_BE_U_4(cp + RRCP_COOKIE1_OFFSET));
	}
	return;

trunc:
	nd_print_trunc(ndo);
}
Beispiel #13
0
void
timed_print(netdissect_options *ndo,
            const u_char *bp)
{
	const struct tsp *tsp = (const struct tsp *)bp;
	uint8_t tsp_type;
	int sec, usec;

	ndo->ndo_protocol = "timed";
	ND_TCHECK_1(tsp->tsp_type);
	tsp_type = EXTRACT_U_1(tsp->tsp_type);
	if (tsp_type < TSPTYPENUMBER)
		ND_PRINT("TSP_%s", tsptype[tsp_type]);
	else
		ND_PRINT("(tsp_type %#x)", tsp_type);

	ND_TCHECK_1(tsp->tsp_vers);
	ND_PRINT(" vers %u", EXTRACT_U_1(tsp->tsp_vers));

	ND_TCHECK_2(tsp->tsp_seq);
	ND_PRINT(" seq %u", EXTRACT_BE_U_2(tsp->tsp_seq));

	switch (tsp_type) {
	case TSP_LOOP:
		ND_TCHECK_1(tsp->tsp_hopcnt);
		ND_PRINT(" hopcnt %u", EXTRACT_U_1(tsp->tsp_hopcnt));
		break;
	case TSP_SETTIME:
	case TSP_ADJTIME:
	case TSP_SETDATE:
	case TSP_SETDATEREQ:
		ND_TCHECK_8(&tsp->tsp_time);
		sec = EXTRACT_BE_S_4(tsp->tsp_time.tv_sec);
		usec = EXTRACT_BE_S_4(tsp->tsp_time.tv_usec);
		/* XXX The comparison below is always false? */
		if (usec < 0)
			/* invalid, skip the rest of the packet */
			return;
		ND_PRINT(" time ");
		if (sec < 0 && usec != 0) {
			sec++;
			if (sec == 0)
				ND_PRINT("-");
			usec = 1000000 - usec;
		}
		ND_PRINT("%d.%06d", sec, usec);
		break;
	}
	ND_PRINT(" name ");
	if (nd_printzp(ndo, tsp->tsp_name, sizeof(tsp->tsp_name),
		       ndo->ndo_snapend))
		goto trunc;
	return;

trunc:
	nd_print_trunc(ndo);
}
Beispiel #14
0
/*
 * print vendor specific attributes
 */
static void
print_vendor_attr(netdissect_options *ndo,
                  const u_char *data, u_int length, u_short attr_code _U_)
{
    u_int idx;
    u_int vendor_id;
    u_int vendor_type;
    u_int vendor_length;

    if (length < 4)
        goto trunc;
    ND_TCHECK_4(data);
    vendor_id = EXTRACT_BE_U_4(data);
    data+=4;
    length-=4;

    ND_PRINT("Vendor: %s (%u)",
           tok2str(smi_values,"Unknown",vendor_id),
           vendor_id);

    while (length >= 2) {
	ND_TCHECK_2(data);

        vendor_type = EXTRACT_U_1(data);
        vendor_length = EXTRACT_U_1(data + 1);

        if (vendor_length < 2)
        {
            ND_PRINT("\n\t    Vendor Attribute: %u, Length: %u (bogus, must be >= 2)",
                   vendor_type,
                   vendor_length);
            return;
        }
        if (vendor_length > length)
        {
            ND_PRINT("\n\t    Vendor Attribute: %u, Length: %u (bogus, goes past end of vendor-specific attribute)",
                   vendor_type,
                   vendor_length);
            return;
        }
        data+=2;
        vendor_length-=2;
        length-=2;
	ND_TCHECK_LEN(data, vendor_length);

        ND_PRINT("\n\t    Vendor Attribute: %u, Length: %u, Value: ",
               vendor_type,
               vendor_length);
        for (idx = 0; idx < vendor_length ; idx++, data++)
            ND_PRINT("%c", ND_ISPRINT(EXTRACT_U_1(data)) ? EXTRACT_U_1(data) : '.');
        length-=vendor_length;
    }
    return;

   trunc:
     nd_print_trunc(ndo);
}
Beispiel #15
0
/*
 * Print NTP control message requests and responses
 */
static void
ntp_control_print(netdissect_options *ndo,
		  const struct ntp_control_data *cd, u_int length)
{
	uint8_t control, R, E, M, opcode;
	uint16_t sequence, status, assoc, offset, count;

	if (length < NTP_CTRLMSG_MINLEN)
		goto invalid;

	ND_TCHECK_1(cd->control);
	control = EXTRACT_U_1(cd->control);
	R = (control & 0x80) != 0;
	E = (control & 0x40) != 0;
	M = (control & 0x20) != 0;
	opcode = control & 0x1f;
	ND_PRINT(", %s, %s, %s, OpCode=%u\n",
		  R ? "Response" : "Request", E ? "Error" : "OK",
		  M ? "More" : "Last", opcode);

	ND_TCHECK_2(cd->sequence);
	sequence = EXTRACT_BE_U_2(cd->sequence);
	ND_PRINT("\tSequence=%hu", sequence);

	ND_TCHECK_2(cd->status);
	status = EXTRACT_BE_U_2(cd->status);
	ND_PRINT(", Status=%#hx", status);

	ND_TCHECK_2(cd->assoc);
	assoc = EXTRACT_BE_U_2(cd->assoc);
	ND_PRINT(", Assoc.=%hu", assoc);

	ND_TCHECK_2(cd->offset);
	offset = EXTRACT_BE_U_2(cd->offset);
	ND_PRINT(", Offset=%hu", offset);

	ND_TCHECK_2(cd->count);
	count = EXTRACT_BE_U_2(cd->count);
	ND_PRINT(", Count=%hu", count);

	if (NTP_CTRLMSG_MINLEN + count > length)
		goto invalid;
	if (count != 0) {
		ND_TCHECK_LEN(cd->data, count);
		ND_PRINT("\n\tTO-BE-DONE: data not interpreted");
	}
	return;

invalid:
	nd_print_invalid(ndo);
	ND_TCHECK_LEN(cd, length);
	return;

trunc:
	nd_print_trunc(ndo);
}
Beispiel #16
0
void
hsrp_print(netdissect_options *ndo, const u_char *bp, u_int len)
{
	const struct hsrp *hp = (const struct hsrp *) bp;
	uint8_t version;

	ndo->ndo_protocol = "hsrp";
	ND_TCHECK_1(hp->hsrp_version);
	version = GET_U_1(hp->hsrp_version);
	ND_PRINT("HSRPv%u", version);
	if (version != 0)
		return;
	ND_TCHECK_1(hp->hsrp_op_code);
	ND_PRINT("-");
	ND_PRINT("%s ",
		 tok2strary(op_code_str, "unknown (%u)", GET_U_1(hp->hsrp_op_code)));
	ND_PRINT("%u: ", len);
	ND_TCHECK_1(hp->hsrp_state);
	ND_PRINT("state=%s ",
		 tok2str(states, "Unknown (%u)", GET_U_1(hp->hsrp_state)));
	ND_TCHECK_1(hp->hsrp_group);
	ND_PRINT("group=%u ", GET_U_1(hp->hsrp_group));
	ND_TCHECK_1(hp->hsrp_reserved);
	if (GET_U_1(hp->hsrp_reserved) != 0) {
		ND_PRINT("[reserved=%u!] ", GET_U_1(hp->hsrp_reserved));
	}
	ND_TCHECK_4(hp->hsrp_virtaddr);
	ND_PRINT("addr=%s", ipaddr_string(ndo, hp->hsrp_virtaddr));
	if (ndo->ndo_vflag) {
		ND_PRINT(" hellotime=");
		unsigned_relts_print(ndo, GET_U_1(hp->hsrp_hellotime));
		ND_PRINT(" holdtime=");
		unsigned_relts_print(ndo, GET_U_1(hp->hsrp_holdtime));
		ND_PRINT(" priority=%u", GET_U_1(hp->hsrp_priority));
		ND_PRINT(" auth=\"");
		if (nd_printn(ndo, hp->hsrp_authdata, sizeof(hp->hsrp_authdata),
			      ndo->ndo_snapend)) {
			ND_PRINT("\"");
			goto trunc;
		}
		ND_PRINT("\"");
	}
	return;
trunc:
	nd_print_trunc(ndo);
}
Beispiel #17
0
static int
ahcp_seconds_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
{
	if (cp + 4 != ep)
		goto invalid;
	ND_TCHECK_4(cp);
	ND_PRINT(": %us", EXTRACT_BE_U_4(cp));
	return 0;

invalid:
	ND_PRINT("%s", istr);
	ND_TCHECK_LEN(cp, ep - cp);
	return 0;
trunc:
	nd_print_trunc(ndo);
	return -1;
}
Beispiel #18
0
static void
ahcp1_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
{
	uint8_t type, mbz;
	uint16_t body_len;

	if (cp + AHCP1_BODY_MIN_LEN > ep)
		goto invalid;
	/* Type */
	ND_TCHECK_1(cp);
	type = EXTRACT_U_1(cp);
	cp += 1;
	/* MBZ */
	ND_TCHECK_1(cp);
	mbz = EXTRACT_U_1(cp);
	cp += 1;
	/* Length */
	ND_TCHECK_2(cp);
	body_len = EXTRACT_BE_U_2(cp);
	cp += 2;

	if (ndo->ndo_vflag) {
		ND_PRINT("\n\t%s", tok2str(ahcp1_msg_str, "Unknown-%u", type));
		if (mbz != 0)
			ND_PRINT(", MBZ %u", mbz);
		ND_PRINT(", Length %u", body_len);
	}
	if (cp + body_len > ep)
		goto invalid;

	/* Options */
	if (ndo->ndo_vflag >= 2)
		ahcp1_options_print(ndo, cp, cp + body_len); /* not ep (ignore extra data) */
	else
		ND_TCHECK_LEN(cp, body_len);
	return;

invalid:
	ND_PRINT("%s", istr);
	ND_TCHECK_LEN(cp, ep - cp);
	return;
trunc:
	nd_print_trunc(ndo);
}
Beispiel #19
0
static void
print_attr_address6(netdissect_options *ndo,
                   const u_char *data, u_int length, u_short attr_code _U_)
{
   if (length != 16)
   {
       ND_PRINT("ERROR: length %u != 16", length);
       return;
   }

   ND_TCHECK_16(data);

   ND_PRINT("%s", ip6addr_string(ndo, data));

   return;

   trunc:
     nd_print_trunc(ndo);
}
Beispiel #20
0
/* XXX should probably pass in the snap header and do checks like arp_print() */
void
aarp_print(netdissect_options *ndo,
           const u_char *bp, u_int length)
{
	const struct aarp *ap;

#define AT(member) ataddr_string(ndo, (ap->member[1]<<8)|ap->member[2],ap->member[3])

	ndo->ndo_protocol = "aarp";
	ND_PRINT("aarp ");
	ap = (const struct aarp *)bp;
	if (!ND_TTEST_SIZE(ap)) {
		/* Just bail if we don't have the whole chunk. */
		nd_print_trunc(ndo);
		return;
	}
	if (length < sizeof(*ap)) {
		ND_PRINT(" [|aarp %u]", length);
		return;
	}
	if (EXTRACT_BE_U_2(ap->htype) == 1 &&
	    EXTRACT_BE_U_2(ap->ptype) == ETHERTYPE_ATALK &&
	    EXTRACT_U_1(ap->halen) == 6 && EXTRACT_U_1(ap->palen) == 4 )
		switch (EXTRACT_BE_U_2(ap->op)) {

		case 1:				/* request */
			ND_PRINT("who-has %s tell %s", AT(pdaddr), AT(psaddr));
			return;

		case 2:				/* response */
			ND_PRINT("reply %s is-at %s", AT(psaddr), etheraddr_string(ndo, ap->hsaddr));
			return;

		case 3:				/* probe (oy!) */
			ND_PRINT("probe %s tell %s", AT(pdaddr), AT(psaddr));
			return;
		}
	ND_PRINT("len %u op %u htype %u ptype %#x halen %u palen %u",
	    length, EXTRACT_BE_U_2(ap->op), EXTRACT_BE_U_2(ap->htype),
	    EXTRACT_BE_U_2(ap->ptype), EXTRACT_U_1(ap->halen), EXTRACT_U_1(ap->palen));
}
Beispiel #21
0
static void
ahcp1_options_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
{
	uint8_t option_no, option_len;

	while (cp < ep) {
		/* Option no */
		ND_TCHECK_1(cp);
		option_no = EXTRACT_U_1(cp);
		cp += 1;
		ND_PRINT("\n\t %s", tok2str(ahcp1_opt_str, "Unknown-%u", option_no));
		if (option_no == AHCP1_OPT_PAD || option_no == AHCP1_OPT_MANDATORY)
			continue;
		/* Length */
		if (cp + 1 > ep)
			goto invalid;
		ND_TCHECK_1(cp);
		option_len = EXTRACT_U_1(cp);
		cp += 1;
		if (cp + option_len > ep)
			goto invalid;
		/* Value */
		if (option_no <= AHCP1_OPT_MAX && data_decoders[option_no] != NULL) {
			if (data_decoders[option_no](ndo, cp, cp + option_len) < 0)
				break; /* truncated and already marked up */
		} else {
			ND_PRINT(" (Length %u)", option_len);
			ND_TCHECK_LEN(cp, option_len);
		}
		cp += option_len;
	}
	return;

invalid:
	ND_PRINT("%s", istr);
	ND_TCHECK_LEN(cp, ep - cp);
	return;
trunc:
	nd_print_trunc(ndo);
}
Beispiel #22
0
/*
 * This is the top level routine of the printer.  'p' points
 * to the ether header of the packet, 'h->ts' is the timestamp,
 * 'h->len' is the length of the packet off the wire, and 'h->caplen'
 * is the number of bytes actually captured.
 */
u_int
ap1394_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
{
	u_int length = h->len;
	u_int caplen = h->caplen;
	const struct firewire_header *fp;
	u_short ether_type;
	struct lladdr_info src, dst;

	ndo->ndo_protocol = "ap1394_if";
	if (caplen < FIREWIRE_HDRLEN) {
		nd_print_trunc(ndo);
		return FIREWIRE_HDRLEN;
	}

	if (ndo->ndo_eflag)
		ap1394_hdr_print(ndo, p, length);

	length -= FIREWIRE_HDRLEN;
	caplen -= FIREWIRE_HDRLEN;
	fp = (const struct firewire_header *)p;
	p += FIREWIRE_HDRLEN;

	ether_type = GET_BE_U_2(fp->firewire_type);
	src.addr = fp->firewire_shost;
	src.addr_string = fwaddr_string;
	dst.addr = fp->firewire_dhost;
	dst.addr_string = fwaddr_string;
	if (ethertype_print(ndo, ether_type, p, length, caplen, &src, &dst) == 0) {
		/* ether_type not known, print raw packet */
		if (!ndo->ndo_eflag)
			ap1394_hdr_print(ndo, (const u_char *)fp, length + FIREWIRE_HDRLEN);

		if (!ndo->ndo_suppress_default_print)
			ND_DEFAULTPRINT(p, caplen);
	}

	return FIREWIRE_HDRLEN;
}
Beispiel #23
0
static int
ahcp_ipv6_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
{
	const char *sep = ": ";

	while (cp < ep) {
		if (cp + 16 > ep)
			goto invalid;
		ND_TCHECK_16(cp);
		ND_PRINT("%s%s", sep, ip6addr_string(ndo, cp));
		cp += 16;
		sep = ", ";
	}
	return 0;

invalid:
	ND_PRINT("%s", istr);
	ND_TCHECK_LEN(cp, ep - cp);
	return 0;
trunc:
	nd_print_trunc(ndo);
	return -1;
}
Beispiel #24
0
static int
ahcp_ipv4_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
{
	const char *sep = ": ";

	while (cp < ep) {
		if (cp + 5 > ep)
			goto invalid;
		ND_TCHECK_5(cp);
		ND_PRINT("%s%s/%u", sep, ipaddr_string(ndo, cp), EXTRACT_U_1(cp + 4));
		cp += 5;
		sep = ", ";
	}
	return 0;

invalid:
	ND_PRINT("%s", istr);
	ND_TCHECK_LEN(cp, ep - cp);
	return 0;
trunc:
	nd_print_trunc(ndo);
	return -1;
}
Beispiel #25
0
/*
 * This is the top level routine of the printer.  'p' points
 * to the ether header of the packet, 'h->ts' is the timestamp,
 * 'h->len' is the length of the packet off the wire, and 'h->caplen'
 * is the number of bytes actually captured.
 */
u_int
pktap_if_print(netdissect_options *ndo,
               const struct pcap_pkthdr *h, const u_char *p)
{
	uint32_t dlt, hdrlen, rectype;
	u_int caplen = h->caplen;
	u_int length = h->len;
	if_printer printer;
	const pktap_header_t *hdr;
	struct pcap_pkthdr nhdr;

	ndo->ndo_protocol = "pktap_if";
	if (caplen < sizeof(pktap_header_t)) {
		nd_print_trunc(ndo);
		return (caplen);
	}
	hdr = (const pktap_header_t *)p;
	dlt = EXTRACT_LE_U_4(hdr->pkt_dlt);
	hdrlen = EXTRACT_LE_U_4(hdr->pkt_len);
	if (hdrlen < sizeof(pktap_header_t)) {
		/*
		 * Claimed header length < structure length.
		 * XXX - does this just mean some fields aren't
		 * being supplied, or is it truly an error (i.e.,
		 * is the length supplied so that the header can
		 * be expanded in the future)?
		 */
		nd_print_trunc(ndo);
		return (caplen);
	}
	if (caplen < hdrlen) {
		nd_print_trunc(ndo);
		return (caplen);
	}

	if (ndo->ndo_eflag)
		pktap_header_print(ndo, p, length);

	length -= hdrlen;
	caplen -= hdrlen;
	p += hdrlen;

	rectype = EXTRACT_LE_U_4(hdr->pkt_rectype);
	switch (rectype) {

	case PKT_REC_NONE:
		ND_PRINT("no data");
		break;

	case PKT_REC_PACKET:
		if ((printer = lookup_printer(dlt)) != NULL) {
			nhdr = *h;
			nhdr.caplen = caplen;
			nhdr.len = length;
			hdrlen += printer(ndo, &nhdr, p);
		} else {
			if (!ndo->ndo_eflag)
				pktap_header_print(ndo, (const u_char *)hdr,
						length + hdrlen);

			if (!ndo->ndo_suppress_default_print)
				ND_DEFAULTPRINT(p, caplen);
		}
		break;
	}

	return (hdrlen);
}
Beispiel #26
0
void
msdp_print(netdissect_options *ndo, const u_char *sp, u_int length)
{
	unsigned int type, len;

	ndo->ndo_protocol = "msdp";
	ND_TCHECK_3(sp);
	/* See if we think we're at the beginning of a compound packet */
	type = EXTRACT_U_1(sp);
	len = EXTRACT_BE_U_2(sp + 1);
	if (len > 1500 || len < 3 || type == 0 || type > MSDP_TYPE_MAX)
		goto trunc;	/* not really truncated, but still not decodable */
	ND_PRINT(" msdp:");
	while (length != 0) {
		ND_TCHECK_3(sp);
		type = EXTRACT_U_1(sp);
		len = EXTRACT_BE_U_2(sp + 1);
		if (len > 1400 || ndo->ndo_vflag)
			ND_PRINT(" [len %u]", len);
		if (len < 3)
			goto trunc;
		if (length < len)
			goto trunc;
		sp += 3;
		length -= 3;
		switch (type) {
		case 1:	/* IPv4 Source-Active */
		case 3: /* IPv4 Source-Active Response */
			if (type == 1)
				ND_PRINT(" SA");
			else
				ND_PRINT(" SA-Response");
			ND_TCHECK_1(sp);
			ND_PRINT(" %u entries", EXTRACT_U_1(sp));
			if ((u_int)((EXTRACT_U_1(sp) * 12) + 8) < len) {
				ND_PRINT(" [w/data]");
				if (ndo->ndo_vflag > 1) {
					ND_PRINT(" ");
					ip_print(ndo, sp +
						 EXTRACT_U_1(sp) * 12 + 8 - 3,
					         len - (EXTRACT_U_1(sp) * 12 + 8));
				}
			}
			break;
		case 2:
			ND_PRINT(" SA-Request");
			ND_TCHECK_5(sp);
			ND_PRINT(" for %s", ipaddr_string(ndo, sp + 1));
			break;
		case 4:
			ND_PRINT(" Keepalive");
			if (len != 3)
				ND_PRINT("[len=%u] ", len);
			break;
		case 5:
			ND_PRINT(" Notification");
			break;
		default:
			ND_PRINT(" [type=%u len=%u]", type, len);
			break;
		}
		sp += (len - 3);
		length -= (len - 3);
	}
	return;
trunc:
	nd_print_trunc(ndo);
}
Beispiel #27
0
void
geneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
{
    uint8_t ver_opt;
    u_int version;
    uint8_t flags;
    uint16_t prot;
    uint32_t vni;
    uint8_t reserved;
    u_int opts_len;

    ndo->ndo_protocol = "geneve";
    ND_PRINT("Geneve");

    ND_TCHECK_8(bp);

    ver_opt = GET_U_1(bp);
    bp += 1;
    len -= 1;

    version = ver_opt >> VER_SHIFT;
    if (version != 0) {
        ND_PRINT(" ERROR: unknown-version %u", version);
        return;
    }

    flags = GET_U_1(bp);
    bp += 1;
    len -= 1;

    prot = GET_BE_U_2(bp);
    bp += 2;
    len -= 2;

    vni = GET_BE_U_3(bp);
    bp += 3;
    len -= 3;

    reserved = GET_U_1(bp);
    bp += 1;
    len -= 1;

    ND_PRINT(", Flags [%s]",
              bittok2str_nosep(geneve_flag_values, "none", flags));
    ND_PRINT(", vni 0x%x", vni);

    if (reserved)
        ND_PRINT(", rsvd 0x%x", reserved);

    if (ndo->ndo_eflag)
        ND_PRINT(", proto %s (0x%04x)",
                  tok2str(ethertype_values, "unknown", prot), prot);

    opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;

    if (len < opts_len) {
        ND_PRINT(" truncated-geneve - %u bytes missing",
                  opts_len - len);
        return;
    }

    ND_TCHECK_LEN(bp, opts_len);

    if (opts_len > 0) {
        ND_PRINT(", options [");

        if (ndo->ndo_vflag)
            geneve_opts_print(ndo, bp, opts_len);
        else
            ND_PRINT("%u bytes", opts_len);

        ND_PRINT("]");
    }

    bp += opts_len;
    len -= opts_len;

    if (ndo->ndo_vflag < 1)
        ND_PRINT(": ");
    else
        ND_PRINT("\n\t");

    if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) {
        if (prot == ETHERTYPE_TEB)
            ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
        else
            ND_PRINT("geneve-proto-0x%x", prot);
    }

    return;

trunc:
    nd_print_trunc(ndo);
}
Beispiel #28
0
void
dvmrp_print(netdissect_options *ndo,
            const u_char *bp, u_int len)
{
	const u_char *ep;
	u_char type;
	uint8_t major_version, minor_version;

	ndo->ndo_protocol = "dvmrp";
	ep = ndo->ndo_snapend;
	if (bp >= ep)
		return;

	ND_TCHECK_1(bp + 1);
	type = GET_U_1(bp + 1);

	/* Skip IGMP header */
	bp += 8;
	len -= 8;

	switch (type) {

	case DVMRP_PROBE:
		ND_PRINT(" Probe");
		if (ndo->ndo_vflag) {
			if (print_probe(ndo, bp, ep, len) < 0)
				goto trunc;
		}
		break;

	case DVMRP_REPORT:
		ND_PRINT(" Report");
		if (ndo->ndo_vflag > 1) {
			if (print_report(ndo, bp, ep, len) < 0)
				goto trunc;
		}
		break;

	case DVMRP_ASK_NEIGHBORS:
		ND_PRINT(" Ask-neighbors(old)");
		break;

	case DVMRP_NEIGHBORS:
		ND_PRINT(" Neighbors(old)");
		if (print_neighbors(ndo, bp, ep, len) < 0)
			goto trunc;
		break;

	case DVMRP_ASK_NEIGHBORS2:
		ND_PRINT(" Ask-neighbors2");
		break;

	case DVMRP_NEIGHBORS2:
		ND_PRINT(" Neighbors2");
		/*
		 * extract version from IGMP group address field
		 */
		bp -= 4;
		ND_TCHECK_4(bp);
		major_version = GET_U_1(bp + 3);
		minor_version = GET_U_1(bp + 2);
		bp += 4;
		if (print_neighbors2(ndo, bp, ep, len, major_version,
		    minor_version) < 0)
			goto trunc;
		break;

	case DVMRP_PRUNE:
		ND_PRINT(" Prune");
		if (print_prune(ndo, bp) < 0)
			goto trunc;
		break;

	case DVMRP_GRAFT:
		ND_PRINT(" Graft");
		if (print_graft(ndo, bp) < 0)
			goto trunc;
		break;

	case DVMRP_GRAFT_ACK:
		ND_PRINT(" Graft-ACK");
		if (print_graft_ack(ndo, bp) < 0)
			goto trunc;
		break;

	default:
		ND_PRINT(" [type %u]", type);
		break;
	}
	return;

trunc:
	nd_print_trunc(ndo);
	return;
}
Beispiel #29
0
void
nsh_print(netdissect_options *ndo, const u_char *bp, u_int len)
{
    u_int n, vn;
    uint8_t ver;
    uint8_t flags;
    u_int length;
    uint8_t md_type;
    uint8_t next_protocol;
    uint32_t service_path_id;
    uint8_t service_index;
    uint32_t ctx;
    uint16_t tlv_class;
    uint8_t tlv_type;
    uint8_t tlv_len;
    u_int next_len;

    ndo->ndo_protocol = "nsh";
    /* print Base Header and Service Path Header */
    if (len < NSH_BASE_HDR_LEN + NSH_SERVICE_PATH_HDR_LEN)
        goto trunc;

    ND_TCHECK_LEN(bp, NSH_BASE_HDR_LEN + NSH_SERVICE_PATH_HDR_LEN);

    ver = (uint8_t)(GET_U_1(bp) >> 6);
    flags = GET_U_1(bp);
    bp += 1;
    length = GET_U_1(bp);
    bp += 1;
    md_type = GET_U_1(bp);
    bp += 1;
    next_protocol = GET_U_1(bp);
    bp += 1;
    service_path_id = GET_BE_U_3(bp);
    bp += 3;
    service_index = GET_U_1(bp);
    bp += 1;

    ND_PRINT("NSH, ");
    if (ndo->ndo_vflag > 1) {
        ND_PRINT("ver %u, ", ver);
    }
    ND_PRINT("flags [%s], ", bittok2str_nosep(nsh_flags, "none", flags));
    if (ndo->ndo_vflag > 2) {
        ND_PRINT("length %u, ", length);
        ND_PRINT("md type 0x%x, ", md_type);
    }
    if (ndo->ndo_vflag > 1) {
        ND_PRINT("next-protocol 0x%x, ", next_protocol);
    }
    ND_PRINT("service-path-id 0x%06x, ", service_path_id);
    ND_PRINT("service-index 0x%x", service_index);

    /* Make sure we have all the headers */
    if (len < length * NSH_HDR_WORD_SIZE)
        goto trunc;

    ND_TCHECK_LEN(bp, length * NSH_HDR_WORD_SIZE);

    /*
     * length includes the lengths of the Base and Service Path headers.
     * That means it must be at least 2.
     */
    if (length < 2)
        goto trunc;

    /*
     * Print, or skip, the Context Headers.
     * (length - 2) is the length of those headers.
     */
    if (ndo->ndo_vflag > 2) {
        if (md_type == 0x01) {
            for (n = 0; n < length - 2; n++) {
                ctx = GET_BE_U_4(bp);
                bp += NSH_HDR_WORD_SIZE;
                ND_PRINT("\n        Context[%02u]: 0x%08x", n, ctx);
            }
        }
        else if (md_type == 0x02) {
            n = 0;
            while (n < length - 2) {
                tlv_class = GET_BE_U_2(bp);
                bp += 2;
                tlv_type  = GET_U_1(bp);
                bp += 1;
                tlv_len   = GET_U_1(bp);
                bp += 1;

                ND_PRINT("\n        TLV Class %u, Type %u, Len %u",
                          tlv_class, tlv_type, tlv_len);

                n += 1;

                if (length - 2 < n + tlv_len) {
                    ND_PRINT(" ERROR: invalid-tlv-length");
                    return;
                }

                for (vn = 0; vn < tlv_len; vn++) {
                    ctx = GET_BE_U_4(bp);
                    bp += NSH_HDR_WORD_SIZE;
                    ND_PRINT("\n            Value[%02u]: 0x%08x", vn, ctx);
                }
                n += tlv_len;
            }
        }
        else {
            ND_PRINT("ERROR: unknown-next-protocol");
            return;
        }
    }
    else {
        bp += (length - 2) * NSH_HDR_WORD_SIZE;
    }
    ND_PRINT(ndo->ndo_vflag ? "\n    " : ": ");

    /* print Next Protocol */
    next_len = len - length * NSH_HDR_WORD_SIZE;
    switch (next_protocol) {
    case 0x1:
        ip_print(ndo, bp, next_len);
        break;
    case 0x2:
        ip6_print(ndo, bp, next_len);
        break;
    case 0x3:
        ether_print(ndo, bp, next_len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
        break;
    default:
        ND_PRINT("ERROR: unknown-next-protocol");
        return;
    }

    return;

trunc:
    nd_print_trunc(ndo);
}
Beispiel #30
0
void
tcp_print(netdissect_options *ndo,
          const u_char *bp, u_int length,
          const u_char *bp2, int fragmented)
{
        const struct tcphdr *tp;
        const struct ip *ip;
        u_char flags;
        u_int hlen;
        char ch;
        uint16_t sport, dport, win, urp;
        uint32_t seq, ack, thseq, thack;
        u_int utoval;
        uint16_t magic;
        int rev;
        const struct ip6_hdr *ip6;

        ndo->ndo_protocol = "tcp";
        tp = (const struct tcphdr *)bp;
        ip = (const struct ip *)bp2;
        if (IP_V(ip) == 6)
                ip6 = (const struct ip6_hdr *)bp2;
        else
                ip6 = NULL;
        ch = '\0';
        if (!ND_TTEST_2(tp->th_dport)) {
                if (ip6) {
                        ND_PRINT("%s > %s:",
                                 ip6addr_string(ndo, ip6->ip6_src),
                                 ip6addr_string(ndo, ip6->ip6_dst));
                } else {
                        ND_PRINT("%s > %s:",
                                 ipaddr_string(ndo, ip->ip_src),
                                 ipaddr_string(ndo, ip->ip_dst));
                }
                nd_print_trunc(ndo);
                return;
        }

        sport = GET_BE_U_2(tp->th_sport);
        dport = GET_BE_U_2(tp->th_dport);

        if (ip6) {
                if (GET_U_1(ip6->ip6_nxt) == IPPROTO_TCP) {
                        ND_PRINT("%s.%s > %s.%s: ",
                                 ip6addr_string(ndo, ip6->ip6_src),
                                 tcpport_string(ndo, sport),
                                 ip6addr_string(ndo, ip6->ip6_dst),
                                 tcpport_string(ndo, dport));
                } else {
                        ND_PRINT("%s > %s: ",
                                 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
                }
        } else {
                if (GET_U_1(ip->ip_p) == IPPROTO_TCP) {
                        ND_PRINT("%s.%s > %s.%s: ",
                                 ipaddr_string(ndo, ip->ip_src),
                                 tcpport_string(ndo, sport),
                                 ipaddr_string(ndo, ip->ip_dst),
                                 tcpport_string(ndo, dport));
                } else {
                        ND_PRINT("%s > %s: ",
                                 tcpport_string(ndo, sport), tcpport_string(ndo, dport));
                }
        }

        ND_TCHECK_SIZE(tp);

        hlen = TH_OFF(tp) * 4;

        if (hlen < sizeof(*tp)) {
                ND_PRINT(" tcp %u [bad hdr length %u - too short, < %lu]",
                         length - hlen, hlen, (unsigned long)sizeof(*tp));
                return;
        }

        seq = GET_BE_U_4(tp->th_seq);
        ack = GET_BE_U_4(tp->th_ack);
        win = GET_BE_U_2(tp->th_win);
        urp = GET_BE_U_2(tp->th_urp);

        if (ndo->ndo_qflag) {
                ND_PRINT("tcp %u", length - hlen);
                if (hlen > length) {
                        ND_PRINT(" [bad hdr length %u - too long, > %u]",
                                 hlen, length);
                }
                return;
        }

        flags = GET_U_1(tp->th_flags);
        ND_PRINT("Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags));

        if (!ndo->ndo_Sflag && (flags & TH_ACK)) {
                /*
                 * Find (or record) the initial sequence numbers for
                 * this conversation.  (we pick an arbitrary
                 * collating order so there's only one entry for
                 * both directions).
                 */
                rev = 0;
                if (ip6) {
                        struct tcp_seq_hash6 *th;
                        struct tcp_seq_hash6 *tcp_seq_hash;
                        const void *src, *dst;
                        struct tha6 tha;

                        tcp_seq_hash = tcp_seq_hash6;
                        src = (const void *)ip6->ip6_src;
                        dst = (const void *)ip6->ip6_dst;
                        if (sport > dport)
                                rev = 1;
                        else if (sport == dport) {
                                if (UNALIGNED_MEMCMP(src, dst, sizeof(ip6->ip6_dst)) > 0)
                                        rev = 1;
                        }
                        if (rev) {
                                UNALIGNED_MEMCPY(&tha.src, dst, sizeof(ip6->ip6_dst));
                                UNALIGNED_MEMCPY(&tha.dst, src, sizeof(ip6->ip6_src));
                                tha.port = ((u_int)dport) << 16 | sport;
                        } else {
                                UNALIGNED_MEMCPY(&tha.dst, dst, sizeof(ip6->ip6_dst));
                                UNALIGNED_MEMCPY(&tha.src, src, sizeof(ip6->ip6_src));
                                tha.port = ((u_int)sport) << 16 | dport;
                        }

                        for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
                             th->nxt; th = th->nxt)
                                if (memcmp((char *)&tha, (char *)&th->addr,
                                           sizeof(th->addr)) == 0)
                                        break;

                        if (!th->nxt || (flags & TH_SYN)) {
                                /* didn't find it or new conversation */
                                /* calloc() return used by the 'tcp_seq_hash6'
                                   hash table: do not free() */
                                if (th->nxt == NULL) {
                                        th->nxt = (struct tcp_seq_hash6 *)
                                                calloc(1, sizeof(*th));
                                        if (th->nxt == NULL)
                                                (*ndo->ndo_error)(ndo,
                                                        S_ERR_ND_MEM_ALLOC,
                                                        "tcp_print: calloc");
                                }
                                th->addr = tha;
                                if (rev)
                                        th->ack = seq, th->seq = ack - 1;
                                else
                                        th->seq = seq, th->ack = ack - 1;
                        } else {
                                if (rev)
                                        seq -= th->ack, ack -= th->seq;
                                else
                                        seq -= th->seq, ack -= th->ack;
                        }

                        thseq = th->seq;
                        thack = th->ack;
                } else {
                        struct tcp_seq_hash *th;
                        struct tcp_seq_hash *tcp_seq_hash;
                        struct tha tha;

                        tcp_seq_hash = tcp_seq_hash4;
                        if (sport > dport)
                                rev = 1;
                        else if (sport == dport) {
                                if (UNALIGNED_MEMCMP(ip->ip_src, ip->ip_dst, sizeof(ip->ip_dst)) > 0)
                                        rev = 1;
                        }
                        if (rev) {
                                UNALIGNED_MEMCPY(&tha.src, ip->ip_dst,
                                                 sizeof(ip->ip_dst));
                                UNALIGNED_MEMCPY(&tha.dst, ip->ip_src,
                                                 sizeof(ip->ip_src));
                                tha.port = ((u_int)dport) << 16 | sport;
                        } else {
                                UNALIGNED_MEMCPY(&tha.dst, ip->ip_dst,
                                                 sizeof(ip->ip_dst));
                                UNALIGNED_MEMCPY(&tha.src, ip->ip_src,
                                                 sizeof(ip->ip_src));
                                tha.port = ((u_int)sport) << 16 | dport;
                        }

                        for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
                             th->nxt; th = th->nxt)
                                if (memcmp((char *)&tha, (char *)&th->addr,
                                           sizeof(th->addr)) == 0)
                                        break;

                        if (!th->nxt || (flags & TH_SYN)) {
                                /* didn't find it or new conversation */
                                /* calloc() return used by the 'tcp_seq_hash4'
                                   hash table: do not free() */
                                if (th->nxt == NULL) {
                                        th->nxt = (struct tcp_seq_hash *)
                                                calloc(1, sizeof(*th));
                                        if (th->nxt == NULL)
                                                (*ndo->ndo_error)(ndo,
                                                        S_ERR_ND_MEM_ALLOC,
                                                        "tcp_print: calloc");
                                }
                                th->addr = tha;
                                if (rev)
                                        th->ack = seq, th->seq = ack - 1;
                                else
                                        th->seq = seq, th->ack = ack - 1;
                        } else {
                                if (rev)
                                        seq -= th->ack, ack -= th->seq;
                                else
                                        seq -= th->seq, ack -= th->ack;
                        }

                        thseq = th->seq;
                        thack = th->ack;
                }
        } else {
                /*fool gcc*/
                thseq = thack = rev = 0;
        }
        if (hlen > length) {
                ND_PRINT(" [bad hdr length %u - too long, > %u]",
                         hlen, length);
                return;
        }

        if (ndo->ndo_vflag && !ndo->ndo_Kflag && !fragmented) {
                /* Check the checksum, if possible. */
                uint16_t sum, tcp_sum;

                if (IP_V(ip) == 4) {
                        if (ND_TTEST_LEN(tp->th_sport, length)) {
                                sum = tcp_cksum(ndo, ip, tp, length);
                                tcp_sum = GET_BE_U_2(tp->th_sum);

                                ND_PRINT(", cksum 0x%04x", tcp_sum);
                                if (sum != 0)
                                        ND_PRINT(" (incorrect -> 0x%04x)",
                                            in_cksum_shouldbe(tcp_sum, sum));
                                else
                                        ND_PRINT(" (correct)");
                        }
                } else if (IP_V(ip) == 6 && ip6->ip6_plen) {
                        if (ND_TTEST_LEN(tp->th_sport, length)) {
                                sum = tcp6_cksum(ndo, ip6, tp, length);
                                tcp_sum = GET_BE_U_2(tp->th_sum);

                                ND_PRINT(", cksum 0x%04x", tcp_sum);
                                if (sum != 0)
                                        ND_PRINT(" (incorrect -> 0x%04x)",
                                            in_cksum_shouldbe(tcp_sum, sum));
                                else
                                        ND_PRINT(" (correct)");

                        }
                }
        }

        length -= hlen;
        if (ndo->ndo_vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) {
                ND_PRINT(", seq %u", seq);

                if (length > 0) {
                        ND_PRINT(":%u", seq + length);
                }
        }

        if (flags & TH_ACK) {
                ND_PRINT(", ack %u", ack);
        }

        ND_PRINT(", win %u", win);

        if (flags & TH_URG)
                ND_PRINT(", urg %u", urp);
        /*
         * Handle any options.
         */
        if (hlen > sizeof(*tp)) {
                const u_char *cp;
                u_int i, opt, datalen;
                u_int len;

                hlen -= sizeof(*tp);
                cp = (const u_char *)tp + sizeof(*tp);
                ND_PRINT(", options [");
                while (hlen > 0) {
                        if (ch != '\0')
                                ND_PRINT("%c", ch);
                        ND_TCHECK_1(cp);
                        opt = GET_U_1(cp);
                        cp++;
                        if (ZEROLENOPT(opt))
                                len = 1;
                        else {
                                ND_TCHECK_1(cp);
                                len = GET_U_1(cp);
                                cp++;	/* total including type, len */
                                if (len < 2 || len > hlen)
                                        goto bad;
                                --hlen;		/* account for length byte */
                        }
                        --hlen;			/* account for type byte */
                        datalen = 0;

/* Bail if "l" bytes of data are not left or were not captured  */
#define LENCHECK(l) { if ((l) > hlen) goto bad; ND_TCHECK_LEN(cp, l); }


                        ND_PRINT("%s", tok2str(tcp_option_values, "unknown-%u", opt));

                        switch (opt) {

                        case TCPOPT_MAXSEG:
                                datalen = 2;
                                LENCHECK(datalen);
                                ND_PRINT(" %u", GET_BE_U_2(cp));
                                break;

                        case TCPOPT_WSCALE:
                                datalen = 1;
                                LENCHECK(datalen);
                                ND_PRINT(" %u", GET_U_1(cp));
                                break;

                        case TCPOPT_SACK:
                                datalen = len - 2;
                                if (datalen % 8 != 0) {
                                        ND_PRINT(" invalid sack");
                                } else {
                                        uint32_t s, e;

                                        ND_PRINT(" %u ", datalen / 8);
                                        for (i = 0; i < datalen; i += 8) {
                                                LENCHECK(i + 4);
                                                s = GET_BE_U_4(cp + i);
                                                LENCHECK(i + 8);
                                                e = GET_BE_U_4(cp + i + 4);
                                                if (rev) {
                                                        s -= thseq;
                                                        e -= thseq;
                                                } else {
                                                        s -= thack;
                                                        e -= thack;
                                                }
                                                ND_PRINT("{%u:%u}", s, e);
                                        }
                                }
                                break;

                        case TCPOPT_CC:
                        case TCPOPT_CCNEW:
                        case TCPOPT_CCECHO:
                        case TCPOPT_ECHO:
                        case TCPOPT_ECHOREPLY:

                                /*
                                 * those options share their semantics.
                                 * fall through
                                 */
                                datalen = 4;
                                LENCHECK(datalen);
                                ND_PRINT(" %u", GET_BE_U_4(cp));
                                break;

                        case TCPOPT_TIMESTAMP:
                                datalen = 8;
                                LENCHECK(datalen);
                                ND_PRINT(" val %u ecr %u",
                                             GET_BE_U_4(cp),
                                             GET_BE_U_4(cp + 4));
                                break;

                        case TCPOPT_SIGNATURE:
                                datalen = TCP_SIGLEN;
                                LENCHECK(datalen);
                                ND_PRINT(" ");
#ifdef HAVE_LIBCRYPTO
                                switch (tcp_verify_signature(ndo, ip, tp,
                                                             bp + TH_OFF(tp) * 4, length, cp)) {

                                case SIGNATURE_VALID:
                                        ND_PRINT("valid");
                                        break;

                                case SIGNATURE_INVALID:
                                        nd_print_invalid(ndo);
                                        break;

                                case CANT_CHECK_SIGNATURE:
                                        ND_PRINT("can't check - ");
                                        for (i = 0; i < TCP_SIGLEN; ++i)
                                                ND_PRINT("%02x",
                                                         GET_U_1(cp + i));
                                        break;
                                }
#else
                                for (i = 0; i < TCP_SIGLEN; ++i)
                                        ND_PRINT("%02x", GET_U_1(cp + i));
#endif
                                break;

                        case TCPOPT_SCPS:
                                datalen = 2;
                                LENCHECK(datalen);
                                ND_PRINT(" cap %02x id %u", GET_U_1(cp),
                                         GET_U_1(cp + 1));
                                break;

                        case TCPOPT_TCPAO:
                                datalen = len - 2;
                                /* RFC 5925 Section 2.2:
                                 * "The Length value MUST be greater than or equal to 4."
                                 * (This includes the Kind and Length fields already processed
                                 * at this point.)
                                 */
                                if (datalen < 2) {
                                        nd_print_invalid(ndo);
                                } else {
                                        LENCHECK(1);
                                        ND_PRINT(" keyid %u", GET_U_1(cp));
                                        LENCHECK(2);
                                        ND_PRINT(" rnextkeyid %u",
                                                 GET_U_1(cp + 1));
                                        if (datalen > 2) {
                                                ND_PRINT(" mac 0x");
                                                for (i = 2; i < datalen; i++) {
                                                        LENCHECK(i + 1);
                                                        ND_PRINT("%02x",
                                                                 GET_U_1(cp + i));
                                                }
                                        }
                                }
                                break;

                        case TCPOPT_EOL:
                        case TCPOPT_NOP:
                        case TCPOPT_SACKOK:
                                /*
                                 * Nothing interesting.
                                 * fall through
                                 */
                                break;

                        case TCPOPT_UTO:
                                datalen = 2;
                                LENCHECK(datalen);
                                utoval = GET_BE_U_2(cp);
                                ND_PRINT(" 0x%x", utoval);
                                if (utoval & 0x0001)
                                        utoval = (utoval >> 1) * 60;
                                else
                                        utoval >>= 1;
                                ND_PRINT(" %u", utoval);
                                break;

                        case TCPOPT_MPTCP:
                                datalen = len - 2;
                                LENCHECK(datalen);
                                if (!mptcp_print(ndo, cp-2, len, flags))
                                        goto bad;
                                break;

                        case TCPOPT_FASTOPEN:
                                datalen = len - 2;
                                LENCHECK(datalen);
                                ND_PRINT(" ");
                                print_tcp_fastopen_option(ndo, cp, datalen, FALSE);
                                break;

                        case TCPOPT_EXPERIMENT2:
                                datalen = len - 2;
                                LENCHECK(datalen);
                                if (datalen < 2)
                                        goto bad;
                                /* RFC6994 */
                                magic = GET_BE_U_2(cp);
                                ND_PRINT("-");

                                switch(magic) {

                                case 0xf989: /* TCP Fast Open RFC 7413 */
                                        print_tcp_fastopen_option(ndo, cp + 2, datalen - 2, TRUE);
                                        break;

                                default:
                                        /* Unknown magic number */
                                        ND_PRINT("%04x", magic);
                                        break;
                                }
                                break;

                        default:
                                datalen = len - 2;
                                if (datalen)
                                        ND_PRINT(" 0x");
                                for (i = 0; i < datalen; ++i) {
                                        LENCHECK(i + 1);
                                        ND_PRINT("%02x", GET_U_1(cp + i));
                                }
                                break;
                        }

                        /* Account for data printed */
                        cp += datalen;
                        hlen -= datalen;

                        /* Check specification against observed length */
                        ++datalen;		/* option octet */
                        if (!ZEROLENOPT(opt))
                                ++datalen;	/* size octet */
                        if (datalen != len)
                                ND_PRINT("[len %u]", len);
                        ch = ',';
                        if (opt == TCPOPT_EOL)
                                break;
                }
                ND_PRINT("]");
        }