617 lines
18 KiB
C
617 lines
18 KiB
C
/*
|
|
* Copyright 1990 Silicon Graphics, Inc. All rights reserved.
|
|
*
|
|
* Protocol Engines Xpress Transfer Protocol (XTP).
|
|
*/
|
|
|
|
#define XTP
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h> /* struct for in_addr */
|
|
#include <netinet/if_ether.h>
|
|
#include "protocols/ip.h" /* enum parameter to pass to ip_hostname */
|
|
#include <sys/socket.h> /* need PF_XTP defined */
|
|
#include "enum.h"
|
|
#include "index.h"
|
|
#include "protodefs.h"
|
|
#include "protocols/xtp.h"
|
|
#include "snooper.h" /* reqd to find XTP trailer */
|
|
|
|
/*
|
|
* Current limitations:
|
|
* can fetch only header fields (not trailer or control segment fields)
|
|
* can't decode any protocols embedded in an XTP packet
|
|
* (i.e., XTP is a leaf protocol, with no match or embed function)
|
|
* doesn't do any byte-swapping of XTP header, trailer, or control segment
|
|
* only decodes addresses of type IP (address format = XTPAF_INET)
|
|
* doesn't cache key/MAC_address associations
|
|
*/
|
|
char xtpname[] = "xtp";
|
|
|
|
/*
|
|
* XTP field identifiers and descriptors.
|
|
*/
|
|
enum xtpfid {
|
|
OPTIONS, OFFSET, LITTLE, VERSION, TYPE, KEY, SORT, HRSVD, SEQ, ROUTE,
|
|
A_LEN, A_FMT, A_RATE, A_ID, A_RSVD,
|
|
AIP_DST, AIP_SRC, AIP_DPORT, AIP_SPORT, AIP_PRO,
|
|
AD_KEY, AD_MAC,
|
|
RATE, BURST, SYNC, XECHO, TIME, TECHO, XKEY, XROUTE, CRSVD, ALLOC,
|
|
RSEQ, NSPAN, SPAN,
|
|
DIAG_C, DIAG_V,
|
|
ROUTE_C, ROUTE_V,
|
|
DCHK, DSEQ, FLAGS, ALIGN, TTL, HTCHK
|
|
};
|
|
|
|
#define XTPF_INHDR(pf) ((pf)->pf_id <= (int) ROUTE)
|
|
#define XTPF_INASEG(pf) ((pf)->pf_id >= (int) A_LEN && \
|
|
(pf)->pf_id <= (int) AIP_PRO)
|
|
#define XTPF_INCSEG(pf) ((pf)->pf_id >= (int) RATE && \
|
|
(pf)->pf_id <= (int) SPAN)
|
|
#define XTPF_INTRLR(pf) ((pf)->pf_id >= (int) DCHK)
|
|
|
|
#define SPAN_SIZE (2 * sizeof(seq_t))
|
|
|
|
static ProtoField xtpfields[] = {
|
|
|
|
/* Header Fields */
|
|
PFI_UINT("options", "Command Options", OPTIONS,u_short,PV_DEFAULT),
|
|
PFI_UINT("offset", "Data Offset", OFFSET, u_char, PV_VERBOSE),
|
|
PFI_UBIT("little", "Little Endian", LITTLE, 1, PV_VERBOSE),
|
|
PFI_UBIT("version", "Version", VERSION,2, PV_VERBOSE),
|
|
PFI_UBIT("type", "Packet Type", TYPE, 5, PV_TERSE),
|
|
PFI_UINT("key", "Key", KEY, u_int, PV_TERSE),
|
|
PFI_UINT("sort", "Priority Sort", SORT, u_int, PV_DEFAULT),
|
|
PFI_UINT("hrsvd", "Reserved Header Field",HRSVD, u_int, PV_VERBOSE+1),
|
|
PFI_UINT("seq", "Sequence Number", SEQ, u_int, PV_TERSE),
|
|
PFI_UINT("route", "Route", ROUTE, u_int, PV_DEFAULT),
|
|
|
|
/* Address Segment Fields */
|
|
PFI_UINT("alength", "Address Segment Length", A_LEN,u_short,PV_VERBOSE),
|
|
PFI_UINT("aformat", "Address Format", A_FMT, u_short,PV_VERBOSE),
|
|
PFI_UINT("arate", "Address Reqested Rate",A_RATE, u_int, PV_VERBOSE),
|
|
PFI_ADDR("aid", "Address Identification",A_ID, 6, PV_VERBOSE),
|
|
PFI_UINT("arsvd", "Address Reserved Field",A_RSVD,u_short,PV_VERBOSE+1),
|
|
PFI_UINT("dsthost", "Destination IP Address", AIP_DST, u_long,PV_TERSE),
|
|
PFI_UINT("srchost", "Source IP Address", AIP_SRC, u_long,PV_TERSE),
|
|
PFI_UINT("dstport", "Destination Port", AIP_DPORT,u_short,PV_TERSE),
|
|
PFI_UINT("srcport", "Source Port", AIP_SPORT,u_short,PV_TERSE),
|
|
PFI_UINT("ipproto", "IP Protocol", AIP_PRO, u_char,PV_DEFAULT),
|
|
|
|
PFI_UINT("daddr", "Direct Address", AD_KEY, u_long, PV_TERSE),
|
|
PFI_UINT("daddrmac","Direct Address MAC", AD_MAC, 6, PV_DEFAULT),
|
|
|
|
/* Control Segment Fields */
|
|
PFI_UINT("rate", "Max Send Rate", RATE, u_long, PV_DEFAULT),
|
|
PFI_UINT("burst","Max Send Burst Size", BURST, u_long, PV_DEFAULT),
|
|
PFI_UINT("sync", "Synchonization ID", SYNC, u_long, PV_DEFAULT),
|
|
PFI_UINT("echo", "Returned Sync Field", XECHO, u_long, PV_DEFAULT),
|
|
PFI_UINT("time", "Time Packet Sent", TIME, u_long, PV_DEFAULT),
|
|
PFI_UINT("techo","Returned Time Field", TECHO, u_long, PV_DEFAULT),
|
|
PFI_UINT("xkey", "Exchanged Key", XKEY, u_long, PV_DEFAULT),
|
|
PFI_UINT("xroute","Exchanged Route", XROUTE, u_long, PV_DEFAULT),
|
|
PFI_UINT("crsvd","Reserved Control Field", CRSVD, u_long, PV_VERBOSE+1),
|
|
PFI_UINT("alloc","Sending Allocation ", ALLOC, u_long, PV_TERSE),
|
|
PFI_UINT("rseq", "Max Rcvd Sequence No", RSEQ, u_long, PV_TERSE),
|
|
PFI_UINT("nspan","Number Rexmt Spans", NSPAN, u_long, PV_TERSE),
|
|
PFI_BYTE("span", "Retransmission Span", SPAN, SPAN_SIZE, PV_TERSE),
|
|
|
|
/* Diag Segment Fields */
|
|
PFI_UINT("dcode", "Diagnostic Code", DIAG_C, u_long, PV_TERSE),
|
|
PFI_UINT("dvalue","Diagnostic Value", DIAG_V, u_long, PV_TERSE),
|
|
|
|
/* Route Segment Fields */
|
|
PFI_UINT("rcode", "Route Code", ROUTE_C, u_long, PV_TERSE),
|
|
PFI_UINT("rvalue", "Route Value", ROUTE_V, u_long, PV_TERSE),
|
|
|
|
/* Trailer Fields */
|
|
PFI_UINT("dcheck", "Data Checksum", DCHK, u_long, PV_VERBOSE),
|
|
PFI_UINT("dseq", "Delivered Seq No", DSEQ, u_long, PV_TERSE),
|
|
PFI_UBIT("tflags", "Trailer Flags", FLAGS, 10, PV_TERSE),
|
|
PFI_UBIT("align", "Trailer Alignment", ALIGN, 6, PV_VERBOSE),
|
|
PFI_UINT("ttl", "Time To Live", TTL, u_short, PV_DEFAULT),
|
|
PFI_UINT("htcheck", "Header/Trailer Checksum",HTCHK, u_long,PV_VERBOSE),
|
|
};
|
|
|
|
#define XTPFID(pf) ((enum xtpfid) (pf)->pf_id)
|
|
#define XTPFIELD(fid) xtpfields[(int) fid]
|
|
|
|
static ProtoMacro xtpnicknames[] = {
|
|
PMI("XTP", xtpname),
|
|
};
|
|
|
|
/*
|
|
* XTP enumerated types.
|
|
*/
|
|
static Enumeration types;
|
|
static Enumerator typesvec[] = {
|
|
EI_VAL("DATA", HT_DATA),
|
|
EI_VAL("CNTL", HT_CNTL),
|
|
EI_VAL("FIRST", HT_FIRST),
|
|
EI_VAL("PATH", HT_PATH),
|
|
EI_VAL("DIAG", HT_DIAG),
|
|
EI_VAL("MAINT", HT_MAINT),
|
|
EI_VAL("MGMT", HT_MGMT),
|
|
EI_VAL("SUPER", HT_SUPER),
|
|
EI_VAL("ROUTE", HT_ROUTE),
|
|
EI_VAL("RCNTL", HT_RCNTL),
|
|
};
|
|
|
|
static Enumeration dcodes;
|
|
static Enumerator dcodesvec[] = {
|
|
EI_VAL("D_UNKNOWN_KEY", DIAG_UNKNOWN_KEY),
|
|
EI_VAL("D_REFUSED", DIAG_CONTEXT_REFUSED),
|
|
EI_VAL("D_UNKNOWN_DEST",DIAG_UNKNOWN_DEST),
|
|
EI_VAL("D_DEAD_HOST", DIAG_DEAD_HOST),
|
|
EI_VAL("D_INVALID_ROUTE",DIAG_INVALID_ROUTE),
|
|
EI_VAL("D_REDIRECT", DIAG_REDIRECT),
|
|
EI_VAL("D_NOROUTE", DIAG_NOROUTE),
|
|
EI_VAL("D_NORESOURCE", DIAG_NORESOURCE),
|
|
EI_VAL("D_PROTERR", DIAG_PROTERR),
|
|
};
|
|
|
|
static Enumeration rcodes;
|
|
static Enumerator rcodesvec[] = {
|
|
EI_VAL("R_RELEASE", RTE_RELEASE),
|
|
EI_VAL("R_RELACK", RTE_RELACK),
|
|
};
|
|
|
|
/*
|
|
* XTP constants.
|
|
*/
|
|
static Enumerator xtpopts[] = {
|
|
EI_VAL("BTAG", HO_BTAG),
|
|
EI_VAL("FASTNAK",HO_FASTNAK),
|
|
EI_VAL("DLINE", HO_DEADLINE),
|
|
EI_VAL("SORT", HO_SORT),
|
|
EI_VAL("RES", HO_RES),
|
|
EI_VAL("MULTI", HO_MULTI),
|
|
EI_VAL("NOERR", HO_NOERR),
|
|
EI_VAL("DADDR", HO_DADDR),
|
|
EI_VAL("NOCHK", HO_NOCHECK),
|
|
EI_VAL("LITTLE",HO_LITTLE),
|
|
};
|
|
|
|
static Enumerator xtpflags[] = {
|
|
EI_VAL("SREQ", TO_SREQ),
|
|
EI_VAL("DREQ", TO_DREQ),
|
|
EI_VAL("RCLOSE",TO_RCLOSE),
|
|
EI_VAL("WCLOSE",TO_WCLOSE),
|
|
EI_VAL("DEFERCK",TO_DEFERCHK),
|
|
EI_VAL("ETAG", TO_ETAG),
|
|
EI_VAL("EOM", TO_EOM),
|
|
EI_VAL("END", TO_END),
|
|
};
|
|
|
|
/*
|
|
* XTP protocol interfaces.
|
|
*/
|
|
#define xtp_setopt pr_stub_setopt
|
|
#define xtp_resolve pr_stub_resolve
|
|
#define xtp_embed pr_stub_embed /* XXX */
|
|
#define xtp_compile pr_stub_compile /* XXX */
|
|
#define xtp_match pr_stub_match /* XXX */
|
|
|
|
static void xtp_decode_cseg(DataStream *ds, PacketView *pv);
|
|
static void xtp_decode_aseg(DataStream *ds, PacketView *pv);
|
|
static void xtp_decode_trailer(DataStream *ds, ProtoStack *ps, PacketView *pv,
|
|
xtp_header *h, u_char *dataptr, int datalen);
|
|
|
|
DefineLeafProtocol(xtp, xtpname, "Xpress Transfer Protocol", PRID_XTP,
|
|
DS_BIG_ENDIAN, sizeof(xtp_header));
|
|
|
|
/*
|
|
* XTP operations.
|
|
*/
|
|
static Index *xtptypes;
|
|
|
|
static int
|
|
xtp_init()
|
|
{
|
|
int nested;
|
|
|
|
if (!pr_register(&xtp_proto, xtpfields, lengthof(xtpfields),
|
|
lengthof(typesvec) + lengthof(dcodesvec)
|
|
+ lengthof(rcodesvec) + lengthof(xtpopts)
|
|
+ lengthof(xtpflags) + 5)) {
|
|
return 0;
|
|
}
|
|
nested = 0;
|
|
if (pr_nest(&xtp_proto, PRID_LOOP, PF_XTP, xtpnicknames,
|
|
lengthof(xtpnicknames))) {
|
|
nested = 1;
|
|
}
|
|
if (pr_nest(&xtp_proto, PRID_ETHER, ETHERTYPE_XTP, xtpnicknames,
|
|
lengthof(xtpnicknames))) {
|
|
nested = 1;
|
|
}
|
|
if (pr_nest(&xtp_proto, PRID_LLC, ETHERTYPE_XTP, xtpnicknames,
|
|
lengthof(xtpnicknames))) {
|
|
nested = 1;
|
|
}
|
|
if (!nested)
|
|
return 0;
|
|
|
|
in_create(1, sizeof(u_short), 0, &xtptypes);
|
|
|
|
en_init(&types, typesvec, lengthof(typesvec), &xtp_proto);
|
|
en_init(&dcodes, dcodesvec, lengthof(dcodesvec), &xtp_proto);
|
|
en_init(&rcodes, rcodesvec, lengthof(rcodesvec), &xtp_proto);
|
|
pr_addnumbers(&xtp_proto, xtpopts, lengthof(xtpopts));
|
|
pr_addnumbers(&xtp_proto, xtpflags, lengthof(xtpflags));
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static int
|
|
xtp_fetch(ProtoField *pf, DataStream *ds, ProtoStack *ps, Expr *rex)
|
|
{
|
|
xtp_header *h;
|
|
|
|
h = (xtp_header *) ds_inline(ds, sizeof *h, sizeof(u_long));
|
|
if (h == 0) {
|
|
if (XTPF_INHDR(pf))
|
|
return ds_field(ds, pf, sizeof *h, rex);
|
|
return 0;
|
|
}
|
|
|
|
switch (XTPFID(pf)) {
|
|
case OPTIONS:
|
|
rex->ex_val = h->options;
|
|
break;
|
|
case OFFSET:
|
|
rex->ex_val = h->offset;
|
|
break;
|
|
case LITTLE:
|
|
rex->ex_val = H_LITTLE(h->type);
|
|
break;
|
|
case VERSION:
|
|
rex->ex_val = H_VERSION(h->type);
|
|
break;
|
|
case TYPE:
|
|
rex->ex_val = H_TYPE(h->type);
|
|
break;
|
|
case KEY:
|
|
rex->ex_val = h->key;
|
|
break;
|
|
case SORT:
|
|
rex->ex_val = h->sort;
|
|
break;
|
|
case SEQ:
|
|
rex->ex_val = h->seq;
|
|
break;
|
|
case ROUTE:
|
|
rex->ex_val = h->route;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
rex->ex_op = EXOP_NUMBER;
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
xtp_decode(DataStream *ds, ProtoStack *ps, PacketView *pv)
|
|
{
|
|
xtp_header *h, hdr;
|
|
u_char *dataptr;
|
|
int datalen;
|
|
|
|
h = (xtp_header *) ds_inline(ds, sizeof *h, sizeof(u_long));
|
|
if (h == 0) {
|
|
h = &hdr;
|
|
(void) ds_bytes(ds, h, MIN(sizeof *h, ds->ds_count));
|
|
}
|
|
|
|
pv_showfield(pv, &XTPFIELD(OPTIONS), &h->options,
|
|
"%-10s", en_bitset(xtpopts, lengthof(xtpopts),
|
|
h->options));
|
|
pv_showfield(pv, &XTPFIELD(OFFSET), &h->offset,
|
|
"%-1u", h->offset);
|
|
pv_showfield(pv, &XTPFIELD(LITTLE), &h->type,
|
|
"%-1u", H_LITTLE(h->type));
|
|
pv_showfield(pv, &XTPFIELD(VERSION), &h->type,
|
|
"%-2u", H_VERSION(h->type));
|
|
if (pv->pv_level >= PV_VERBOSE)
|
|
pv_break(pv);
|
|
pv_showfield(pv, &XTPFIELD(TYPE), &h->type,
|
|
"%-6.6s", en_name(&types, H_TYPE(h->type)));
|
|
pv_showfield(pv, &XTPFIELD(KEY), &h->key,
|
|
"%-#8x", h->key);
|
|
pv_showfield(pv, &XTPFIELD(SORT), &h->sort,
|
|
"%-10u", h->sort);
|
|
pv_showfield(pv, &XTPFIELD(HRSVD), &h->reserved,
|
|
"%-10u", h->reserved);
|
|
pv_showfield(pv, &XTPFIELD(SEQ), &h->seq,
|
|
"%-10u", h->seq);
|
|
pv_showfield(pv, &XTPFIELD(ROUTE), &h->route,
|
|
"%-#8x", h->route);
|
|
pv_break(pv);
|
|
|
|
/*
|
|
* Skip over padding between XTP header and information segment
|
|
* XXX perhaps later make this a "triple verbose" field?
|
|
*/
|
|
if (h->offset) {
|
|
ds_seek(ds, h->offset, DS_RELATIVE);
|
|
pv->pv_off += h->offset;
|
|
}
|
|
|
|
/*
|
|
* Save some info so I can calculate checksums over addr & cntl segs
|
|
*/
|
|
dataptr = ds->ds_next;
|
|
datalen = ds->ds_count - sizeof (xtp_trailer);
|
|
|
|
switch (H_TYPE(h->type)) {
|
|
case HT_FIRST:
|
|
case HT_PATH:
|
|
xtp_decode_aseg(ds, pv);
|
|
break;
|
|
case HT_CNTL:
|
|
case HT_RCNTL:
|
|
xtp_decode_cseg(ds, pv);
|
|
break;
|
|
|
|
case HT_DIAG: {
|
|
xtp_diag *dseg, diag_seg;
|
|
|
|
dseg = (xtp_diag *)
|
|
ds_inline(ds, sizeof *dseg, sizeof(u_long));
|
|
if (dseg == 0) {
|
|
dseg = &diag_seg;
|
|
(void) ds_bytes(ds, dseg,
|
|
MIN(sizeof *dseg, ds->ds_count));
|
|
}
|
|
pv_showfield(pv, &XTPFIELD(DIAG_C), &dseg->code,
|
|
"%-15.15s", en_name(&dcodes, dseg->code));
|
|
pv_showfield(pv, &XTPFIELD(DIAG_V), &dseg->value,
|
|
"%-8d", dseg->value);
|
|
/* XXX what is format of dseg->msg ? */
|
|
break;
|
|
}
|
|
|
|
case HT_ROUTE: {
|
|
xtp_route *rseg, route_seg;
|
|
|
|
rseg = (xtp_route *)
|
|
ds_inline(ds, sizeof *rseg, sizeof(u_long));
|
|
if (rseg == 0) {
|
|
printf ("ds_inline failed\n");
|
|
rseg = &route_seg;
|
|
(void) ds_bytes(ds, rseg,
|
|
MIN(sizeof *rseg, ds->ds_count));
|
|
}
|
|
pv_showfield(pv, &XTPFIELD(ROUTE_C), &rseg->code,
|
|
"%-15.15s", en_name(&rcodes, rseg->code));
|
|
pv_showfield(pv, &XTPFIELD(ROUTE_V), &rseg->value,
|
|
"%-8d", rseg->value);
|
|
/* XXX what is format of rseg->msg ? */
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
pv_decodeframe(pv, NULL, ds, ps);
|
|
xtp_decode_trailer(ds, ps, pv, h, dataptr, datalen);
|
|
}
|
|
|
|
static void
|
|
xtp_decode_cseg(DataStream *ds, PacketView *pv)
|
|
{
|
|
xtp_cseg *cseg, cntl_seg;
|
|
int i, skiplen;
|
|
seq_t *xspan;
|
|
seq_t skipdata[2*MAX_SPAN];
|
|
|
|
cseg = (xtp_cseg *) ds_inline(ds, CSEG_MINLEN, sizeof(u_long));
|
|
if (cseg == 0) {
|
|
cseg = &cntl_seg;
|
|
(void) ds_bytes(ds, cseg, MIN(CSEG_MINLEN, ds->ds_count));
|
|
}
|
|
|
|
pv_showfield(pv, &XTPFIELD(RATE), &cseg->rate,
|
|
"%-10u", cseg->rate);
|
|
pv_showfield(pv, &XTPFIELD(BURST), &cseg->burst,
|
|
"%-10u", cseg->burst);
|
|
pv_showfield(pv, &XTPFIELD(SYNC), &cseg->sync,
|
|
"%-10u", cseg->sync);
|
|
pv_showfield(pv, &XTPFIELD(XECHO), &cseg->echo,
|
|
"%-10u", cseg->echo);
|
|
pv_showfield(pv, &XTPFIELD(TIME), &cseg->time,
|
|
"%-10u", cseg->time);
|
|
pv_showfield(pv, &XTPFIELD(TECHO), &cseg->timeecho,
|
|
"%-10u", cseg->timeecho);
|
|
pv_showfield(pv, &XTPFIELD(XKEY), &cseg->xkey,
|
|
"%-#8x", cseg->xkey);
|
|
pv_showfield(pv, &XTPFIELD(XROUTE), &cseg->xroute,
|
|
"%-#8x", cseg->xroute);
|
|
pv_showfield(pv, &XTPFIELD(CRSVD), &cseg->reserved,
|
|
"%-10u", cseg->reserved);
|
|
pv_showfield(pv, &XTPFIELD(ALLOC), &cseg->alloc,
|
|
"%-10u", cseg->alloc);
|
|
pv_showfield(pv, &XTPFIELD(RSEQ), &cseg->rseq,
|
|
"%-10u", cseg->rseq);
|
|
pv_showfield(pv, &XTPFIELD(NSPAN), &cseg->nspan,
|
|
"%-10u", cseg->nspan);
|
|
|
|
for (i = MIN(cseg->nspan, MAX_SPAN); i > 0; --i) {
|
|
xspan = (seq_t *)
|
|
ds_inline(ds, 2*sizeof(seq_t), sizeof(u_long));
|
|
if (xspan != 0) {
|
|
pv_showfield(pv, &XTPFIELD(SPAN), xspan,
|
|
"%u:%u", xspan[0], xspan[1]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* There may be more spans in the packet format than indicated by
|
|
* nspan. So skip to the XTP trailer so these unused spans aren't
|
|
* interpreted as data.
|
|
* XXX Perhaps later make this a "triple verbose" field?
|
|
*/
|
|
|
|
if (pv->pv_level >= PV_VERBOSE+1) {
|
|
skiplen = ds->ds_size - sizeof (xtp_trailer) - DS_TELL(ds);
|
|
if (skiplen > 0)
|
|
pv_decodehex(pv, ds, 0, skiplen);
|
|
} else {
|
|
ds_seek(ds, ds->ds_size - sizeof (xtp_trailer), DS_ABSOLUTE);
|
|
pv->pv_off = DS_TELL(ds);
|
|
}
|
|
}
|
|
|
|
static void
|
|
xtp_decode_aseg(DataStream *ds, PacketView *pv)
|
|
{
|
|
xtp_addr *aseg, addr_seg;
|
|
|
|
aseg = (xtp_addr *) ds_inline(ds, ADDRSEG_MINLEN, sizeof(u_long));
|
|
if (aseg == 0) {
|
|
aseg = &addr_seg;
|
|
(void) ds_bytes(ds, aseg,
|
|
MIN(ADDRSEG_MINLEN, ds->ds_count));
|
|
}
|
|
|
|
(void) ds_bytes(ds, &aseg->addr,
|
|
MIN(aseg->length - ADDRSEG_MINLEN, ds->ds_count));
|
|
|
|
pv_showfield(pv, &XTPFIELD(A_LEN), &aseg->length,
|
|
"%-5u", aseg->length);
|
|
pv_showfield(pv, &XTPFIELD(A_FMT), &aseg->format,
|
|
"%#04x", aseg->format);
|
|
pv_showfield(pv, &XTPFIELD(A_RATE), &aseg->ratereq,
|
|
"%-10u", aseg->ratereq);
|
|
pv_showfield(pv, &XTPFIELD(A_ID), aseg->id,
|
|
"%-25.25s", ether_hostname(aseg->id));
|
|
pv_showfield(pv, &XTPFIELD(A_RSVD), &aseg->reserved,
|
|
"%-5u", aseg->reserved);
|
|
|
|
if (pv->pv_level >= PV_VERBOSE)
|
|
pv_break(pv);
|
|
|
|
switch (aseg->format) {
|
|
case XTPAF_INET: {
|
|
char *protoname;
|
|
struct in_addr tmp_addr;
|
|
Protocol *spr, *dpr;
|
|
|
|
/* XXX can clean up this junk if IP addresses in xtp.h are type in_addr */
|
|
tmp_addr.s_addr = aseg->addr.inet.dstaddr;
|
|
pv_showfield(pv, &XTPFIELD(AIP_DST), &aseg->addr.inet.dstaddr,
|
|
"%-21.21s", ip_hostname(tmp_addr, IP_HOST));
|
|
|
|
tmp_addr.s_addr = aseg->addr.inet.srcaddr;
|
|
pv_showfield(pv, &XTPFIELD(AIP_SRC), &aseg->addr.inet.srcaddr,
|
|
"%-21.21s", ip_hostname(tmp_addr, IP_HOST));
|
|
|
|
pv_break(pv); /* get ports to line up w/ IP addresses */
|
|
|
|
protoname = ip_protoname(aseg->addr.inet.ipproto);
|
|
spr = dpr = NULL;
|
|
pv_showfield(pv, &XTPFIELD(AIP_DPORT), &aseg->addr.inet.dstport,
|
|
"%-21.21s", ip_service(aseg->addr.inet.dstport,
|
|
protoname, spr));
|
|
pv_showfield(pv, &XTPFIELD(AIP_SPORT), &aseg->addr.inet.srcport,
|
|
"%-21.21s", ip_service(aseg->addr.inet.srcport,
|
|
protoname, dpr));
|
|
pv_showfield(pv, &XTPFIELD(AIP_PRO), &aseg->addr.inet.ipproto,
|
|
"%-6s", protoname);
|
|
break;
|
|
} /* case of XTPAF_INET */
|
|
|
|
case XTPAF_DADDR:
|
|
pv_showfield(pv, &XTPFIELD(AD_KEY), &aseg->addr.daddr.key,
|
|
"%-#8x", aseg->addr.daddr.key);
|
|
break;
|
|
|
|
case XTPAF_ISO:
|
|
case XTPAF_XNS:
|
|
default:
|
|
pv_showhex(pv, (unsigned char *) &aseg,
|
|
ADDRSEG_MINLEN, aseg->length);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
xtp_decode_trailer(DataStream *ds, ProtoStack *ps, PacketView *pv,
|
|
xtp_header *h, u_char *dataptr, int datalen)
|
|
{
|
|
xtp_trailer *t;
|
|
u_long chksum;
|
|
int saved_offset, saved_pvoff, skip;
|
|
|
|
/*
|
|
* If we didn't capture entire XTP trailer, don't try to decode it
|
|
*/
|
|
|
|
if (ps->ps_snoop->sn_rawproto->pr_maxhdrlen + ds->ds_size
|
|
< ps->ps_snhdr->snoop_packetlen)
|
|
return;
|
|
|
|
saved_offset = DS_TELL(ds);
|
|
saved_pvoff = pv->pv_off;
|
|
ds_seek(ds, ds->ds_size - sizeof *t, DS_ABSOLUTE);
|
|
pv->pv_off = DS_TELL(ds);
|
|
t = (xtp_trailer *) ds_inline(ds, sizeof *t, sizeof(u_long));
|
|
if (t == 0)
|
|
skip = 0;
|
|
else {
|
|
/* earlier check should be sufficient, but let's be sure */
|
|
pv_break(pv);
|
|
|
|
if (t->flags & TO_DEFERCHK) {
|
|
chksum = t->dcheck;
|
|
} else {
|
|
chksum = xtp_long_catxor(dataptr, datalen, 0);
|
|
}
|
|
if (t->dcheck == chksum) {
|
|
pv_showfield(pv, &XTPFIELD(DCHK), &t->dcheck,
|
|
"%#010x", t->dcheck);
|
|
} else {
|
|
pv_showfield(pv, &XTPFIELD(DCHK), &t->dcheck,
|
|
"%#010x [!= %#010x]", t->dcheck, chksum);
|
|
}
|
|
pv_showfield(pv, &XTPFIELD(DSEQ), &t->dseq, "%-10u", t->dseq);
|
|
|
|
/* can't pass addr of bit field */
|
|
pv_showfield(pv, &XTPFIELD(FLAGS), &t->dseq + 1,
|
|
"%-18s", en_bitset(xtpflags, lengthof(xtpflags),
|
|
t->flags));
|
|
|
|
if (pv->pv_level >= PV_VERBOSE)
|
|
pv_break(pv);
|
|
pv_showfield(pv, &XTPFIELD(ALIGN), &t->dseq + 1,
|
|
"%-2u", t->align);
|
|
pv_showfield(pv, &XTPFIELD(TTL), &t->ttl, "%-5u", t->ttl);
|
|
|
|
if (h->options & HO_NOCHECK) {
|
|
chksum = t->htcheck;
|
|
} else {
|
|
chksum = xtp_htcheck(h, t);
|
|
}
|
|
if (t->htcheck != chksum) {
|
|
pv_showfield(pv, &XTPFIELD(HTCHK), &t->htcheck,
|
|
"%#010x [!= %#010x]", t->htcheck, chksum);
|
|
} else {
|
|
pv_showfield(pv, &XTPFIELD(HTCHK), &t->htcheck,
|
|
"%#010x", t->htcheck);
|
|
}
|
|
|
|
skip = sizeof *t + t->align;
|
|
}
|
|
/*
|
|
* Restore datastream so we can decode info between XTP hdr and trlr
|
|
* But reduce count so we don't interpret XTP trailer as data.
|
|
*/
|
|
ds_seek(ds, saved_offset, DS_ABSOLUTE);
|
|
ds->ds_count -= skip;
|
|
ds->ds_size -= skip;
|
|
pv->pv_off = saved_pvoff;
|
|
}
|
|
|