rx_print(netdissect_options *ndo,
         const u_char *bp, u_int length, u_int sport, u_int dport,
         const u_char *bp2)
{
	const struct rx_header *rxh;
	uint32_t i;
	uint8_t type, flags;
	uint32_t opcode;

	ndo->ndo_protocol = "rx";
	if (!ND_TTEST_LEN(bp, sizeof(struct rx_header))) {
		ND_PRINT(" [|rx] (%u)", length);
		return;
	}

	rxh = (const struct rx_header *) bp;

	type = EXTRACT_U_1(rxh->type);
	ND_PRINT(" rx %s", tok2str(rx_types, "type %u", type));

	flags = EXTRACT_U_1(rxh->flags);
	if (ndo->ndo_vflag) {
		int firstflag = 0;

		if (ndo->ndo_vflag > 1)
			ND_PRINT(" cid %08x call# %u",
			       EXTRACT_BE_U_4(rxh->cid),
			       EXTRACT_BE_U_4(rxh->callNumber));

		ND_PRINT(" seq %u ser %u",
		       EXTRACT_BE_U_4(rxh->seq),
		       EXTRACT_BE_U_4(rxh->serial));

		if (ndo->ndo_vflag > 2)
			ND_PRINT(" secindex %u serviceid %hu",
				EXTRACT_U_1(rxh->securityIndex),
				EXTRACT_BE_U_2(rxh->serviceId));

		if (ndo->ndo_vflag > 1)
			for (i = 0; i < NUM_RX_FLAGS; i++) {
				if (flags & rx_flags[i].flag &&
				    (!rx_flags[i].packetType ||
				     type == rx_flags[i].packetType)) {
					if (!firstflag) {
						firstflag = 1;
						ND_PRINT(" ");
					} else {
						ND_PRINT(",");
					}
					ND_PRINT("<%s>", rx_flags[i].s);
				}
			}
	}

	/*
	 * Try to handle AFS calls that we know about.  Check the destination
	 * port and make sure it's a data packet.  Also, make sure the
	 * seq number is 1 (because otherwise it's a continuation packet,
	 * and we can't interpret that).  Also, seems that reply packets
	 * do not have the client-init flag set, so we check for that
	 * as well.
	 */

	if (type == RX_PACKET_TYPE_DATA &&
	    EXTRACT_BE_U_4(rxh->seq) == 1 &&
	    flags & RX_CLIENT_INITIATED) {

		/*
		 * Insert this call into the call cache table, so we
		 * have a chance to print out replies
		 */

		rx_cache_insert(ndo, bp, (const struct ip *) bp2, dport);

		switch (dport) {
			case FS_RX_PORT:	/* AFS file service */
				fs_print(ndo, bp, length);
				break;
			case CB_RX_PORT:	/* AFS callback service */
				cb_print(ndo, bp, length);
				break;
			case PROT_RX_PORT:	/* AFS protection service */
				prot_print(ndo, bp, length);
				break;
			case VLDB_RX_PORT:	/* AFS VLDB service */
				vldb_print(ndo, bp, length);
				break;
			case KAUTH_RX_PORT:	/* AFS Kerberos auth service */
				kauth_print(ndo, bp, length);
				break;
			case VOL_RX_PORT:	/* AFS Volume service */
				vol_print(ndo, bp, length);
				break;
			case BOS_RX_PORT:	/* AFS BOS service */
				bos_print(ndo, bp, length);
				break;
			default:
				;
		}

	/*
	 * If it's a reply (client-init is _not_ set, but seq is one)
	 * then look it up in the cache.  If we find it, call the reply
	 * printing functions  Note that we handle abort packets here,
	 * because printing out the return code can be useful at times.
	 */

	} else if (((type == RX_PACKET_TYPE_DATA &&
					EXTRACT_BE_U_4(rxh->seq) == 1) ||
		    type == RX_PACKET_TYPE_ABORT) &&
		   (flags & RX_CLIENT_INITIATED) == 0 &&
		   rx_cache_find(rxh, (const struct ip *) bp2,
				 sport, &opcode)) {

		switch (sport) {
			case FS_RX_PORT:	/* AFS file service */
				fs_reply_print(ndo, bp, length, opcode);
				break;
			case CB_RX_PORT:	/* AFS callback service */
				cb_reply_print(ndo, bp, length, opcode);
				break;
			case PROT_RX_PORT:	/* AFS PT service */
				prot_reply_print(ndo, bp, length, opcode);
				break;
			case VLDB_RX_PORT:	/* AFS VLDB service */
				vldb_reply_print(ndo, bp, length, opcode);
				break;
			case KAUTH_RX_PORT:	/* AFS Kerberos auth service */
				kauth_reply_print(ndo, bp, length, opcode);
				break;
			case VOL_RX_PORT:	/* AFS Volume service */
				vol_reply_print(ndo, bp, length, opcode);
				break;
			case BOS_RX_PORT:	/* AFS BOS service */
				bos_reply_print(ndo, bp, length, opcode);
				break;
			default:
				;
		}

	/*
	 * If it's an RX ack packet, then use the appropriate ack decoding
	 * function (there isn't any service-specific information in the
	 * ack packet, so we can use one for all AFS services)
	 */

	} else if (type == RX_PACKET_TYPE_ACK)
		rx_ack_print(ndo, bp, length);


	ND_PRINT(" (%u)", length);
}
rx_print(netdissect_options *ndo,
         const u_char *bp, u_int length, u_int sport, u_int dport,
         const u_char *bp2)
{
	const struct rx_header *rxh;
	uint32_t i;
	uint8_t type, flags;
	uint32_t opcode;

	ndo->ndo_protocol = "rx";
	if (!ND_TTEST_LEN(bp, sizeof(struct rx_header))) {
		ND_PRINT(" [|rx] (%u)", length);
		return;
	}

	rxh = (const struct rx_header *) bp;

	type = EXTRACT_U_1(rxh->type);
	ND_PRINT(" rx %s", tok2str(rx_types, "type %u", type));

	flags = EXTRACT_U_1(rxh->flags);
	if (ndo->ndo_vflag) {
		int firstflag = 0;

		if (ndo->ndo_vflag > 1)
			ND_PRINT(" cid %08x call# %u",
			       EXTRACT_BE_U_4(rxh->cid),
			       EXTRACT_BE_U_4(rxh->callNumber));

		ND_PRINT(" seq %u ser %u",
		       EXTRACT_BE_U_4(rxh->seq),
		       EXTRACT_BE_U_4(rxh->serial));

		if (ndo->ndo_vflag > 2)
			ND_PRINT(" secindex %u serviceid %hu",
				EXTRACT_U_1(rxh->securityIndex),
				EXTRACT_BE_U_2(rxh->serviceId));

		if (ndo->ndo_vflag > 1)
			for (i = 0; i < NUM_RX_FLAGS; i++) {
				if (flags & rx_flags[i].flag &&
				    (!rx_flags[i].packetType ||
				     type == rx_flags[i].packetType)) {
					if (!firstflag) {
						firstflag = 1;
						ND_PRINT(" ");
					} else {
						ND_PRINT(",");
					}
					ND_PRINT("<%s>", rx_flags[i].s);
				}
			}
	}

	 

	if (type == RX_PACKET_TYPE_DATA &&
	    EXTRACT_BE_U_4(rxh->seq) == 1 &&
	    flags & RX_CLIENT_INITIATED) {

		 

		rx_cache_insert(ndo, bp, (const struct ip *) bp2, dport);

		switch (dport) {
			case FS_RX_PORT:	 
				fs_print(ndo, bp, length);
				break;
			case CB_RX_PORT:	 
				cb_print(ndo, bp, length);
				break;
			case PROT_RX_PORT:	 
				prot_print(ndo, bp, length);
				break;
			case VLDB_RX_PORT:	 
				vldb_print(ndo, bp, length);
				break;
			case KAUTH_RX_PORT:	 
				kauth_print(ndo, bp, length);
				break;
			case VOL_RX_PORT:	 
				vol_print(ndo, bp, length);
				break;
			case BOS_RX_PORT:	 
				bos_print(ndo, bp, length);
				break;
			default:
				;
		}

	 

	} else if (((type == RX_PACKET_TYPE_DATA &&
					EXTRACT_BE_U_4(rxh->seq) == 1) ||
		    type == RX_PACKET_TYPE_ABORT) &&
		   (flags & RX_CLIENT_INITIATED) == 0 &&
		   rx_cache_find(rxh, (const struct ip *) bp2,
				 sport, &opcode)) {

		switch (sport) {
			case FS_RX_PORT:	 
				fs_reply_print(ndo, bp, length, opcode);
				break;
			case CB_RX_PORT:	 
				cb_reply_print(ndo, bp, length, opcode);
				break;
			case PROT_RX_PORT:	 
				prot_reply_print(ndo, bp, length, opcode);
				break;
			case VLDB_RX_PORT:	 
				vldb_reply_print(ndo, bp, length, opcode);
				break;
			case KAUTH_RX_PORT:	 
				kauth_reply_print(ndo, bp, length, opcode);
				break;
			case VOL_RX_PORT:	 
				vol_reply_print(ndo, bp, length, opcode);
				break;
			case BOS_RX_PORT:	 
				bos_reply_print(ndo, bp, length, opcode);
				break;
			default:
				;
		}

	 

	} else if (type == RX_PACKET_TYPE_ACK)
		rx_ack_print(ndo, bp, length);


	ND_PRINT(" (%u)", length);
}