2 * Routines for XIP dissection
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * The eXpressive Internet Protocol (XIP) is the network layer protocol for
23 * the eXpressive Internet Architecture (XIA), a future Internet architecture
24 * project. The addresses in XIP are directed acyclic graphs, so some of the
25 * code in this file verifies the correctness of the DAGs and displays them
26 * in human-readable form.
28 * More information about XIA can be found here:
29 * https://www.cs.cmu.edu/~xia/
32 * https://github.com/AltraMayor/XIA-for-Linux/wiki
34 * More information about the format of the DAG can be found here:
35 * https://github.com/AltraMayor/XIA-for-Linux/wiki/Human-readable-XIP-address-format
39 #include <epan/packet.h>
40 #include <epan/expert.h>
42 void proto_register_xip(void);
43 void proto_reg_handoff_xip(void);
45 /* Next dissector handles. */
46 static dissector_handle_t data_handle;
48 static gint proto_xip = -1;
50 static gint hf_xip_version = -1;
51 static gint hf_xip_next_hdr = -1;
52 static gint hf_xip_payload_len = -1;
53 static gint hf_xip_hop_limit = -1;
54 static gint hf_xip_num_dst = -1;
55 static gint hf_xip_num_src = -1;
56 static gint hf_xip_last_node = -1;
57 static gint hf_xip_dst_dag = -1;
58 static gint hf_xip_dst_dag_entry = -1;
59 static gint hf_xip_src_dag = -1;
60 static gint hf_xip_src_dag_entry = -1;
62 static gint ett_xip_tree = -1;
63 static gint ett_xip_ddag = -1;
64 static gint ett_xip_sdag = -1;
66 static expert_field ei_xip_invalid_len = EI_INIT;
67 static expert_field ei_xip_next_header = EI_INIT;
68 static expert_field ei_xip_bad_num_dst = EI_INIT;
69 static expert_field ei_xip_bad_num_src = EI_INIT;
72 #define XIDTYPE_NAT 0x00
73 #define XIDTYPE_AD 0x10
74 #define XIDTYPE_HID 0x11
75 #define XIDTYPE_CID 0x12
76 #define XIDTYPE_SID 0x13
77 #define XIDTYPE_UNI4ID 0x14
78 #define XIDTYPE_I4ID 0x15
79 #define XIDTYPE_U4ID 0x16
80 #define XIDTYPE_XDP 0x17
81 #define XIDTYPE_SRVCID 0x18
82 #define XIDTYPE_FLOWID 0x19
83 #define XIDTYPE_ZF 0x20
85 /* Principal string values. */
86 static const value_string xidtype_vals[] = {
88 { XIDTYPE_HID, "hid" },
89 { XIDTYPE_CID, "cid" },
90 { XIDTYPE_SID, "sid" },
91 { XIDTYPE_UNI4ID, "uni4id" },
92 { XIDTYPE_I4ID, "i4id" },
93 { XIDTYPE_U4ID, "u4id" },
94 { XIDTYPE_XDP, "xdp" },
95 { XIDTYPE_SRVCID, "serval" },
96 { XIDTYPE_FLOWID, "flowid" },
101 enum xia_addr_error {
102 /* There's a non-XIDTYPE_NAT node after an XIDTYPE_NAT node. */
103 XIAEADDR_NAT_MISPLACED = 1,
104 /* Edge-selected bit is only valid in packets. */
105 XIAEADDR_CHOSEN_EDGE,
106 /* There's a non-empty edge after an Empty Edge.
107 * This error can also occur if an empty edge is selected. */
108 XIAEADDR_EE_MISPLACED,
109 /* An edge of a node is out of range. */
110 XIAEADDR_EDGE_OUT_RANGE,
111 /* The nodes are not in topological order. Notice that being in
112 * topological guarantees that the graph is acyclic, and has a simple,
114 XIAEADDR_NOT_TOPOLOGICAL,
115 /* No single component. */
116 XIAEADDR_MULTI_COMPONENTS,
117 /* Entry node is not present. */
121 /* Maximum number of nodes in a DAG. */
122 #define XIA_NODES_MAX 9
124 /* Number of outgoing edges for each node. */
125 #define XIA_OUTDEGREE_MAX 4
127 /* Sizes of an XIA node and its components. */
128 #define XIA_TYPE_SIZE 4
129 #define XIA_XID_SIZE 20
130 #define XIA_EDGES_SIZE 4
131 #define XIA_NODE_SIZE (XIA_TYPE_SIZE + XIA_XID_SIZE + XIA_EDGES_SIZE)
133 /* Split XID up into 4 byte chunks. */
134 #define XIA_XID_CHUNK_SIZE 4
136 typedef guint32 xid_type_t;
142 /* XID, represented as 4 byte ints. */
143 guint32 xid_id[XIA_XID_SIZE / XIA_XID_CHUNK_SIZE];
147 struct xia_xid s_xid;
148 /* Outgoing edges. */
150 guint8 a[XIA_OUTDEGREE_MAX];
156 struct xia_row s_row[XIA_NODES_MAX];
159 /* XIA_MAX_STRADDR_SIZE - The maximum size of an XIA address as a string
160 * in bytes. It's the recommended size to call xia_ntop with. It includes space
161 * for an invalid sign (i.e. '!'), the type and name of a nodes in
162 * hexadecimal, the out-edges, the two separators (i.e. '-') per node,
163 * the edge-chosen sign (i.e. '>') for each selected edge,
164 * the node separators (i.e. ':' or ":\n"), a string terminator (i.e. '\0'),
165 * and an extra '\n' at the end the caller may want to add.
167 #define MAX_PPAL_NAME_SIZE 32
168 #define XIA_MAX_STRID_SIZE (XIA_XID_SIZE * 2 + 1)
169 #define XIA_MAX_STRXID_SIZE (MAX_PPAL_NAME_SIZE + XIA_MAX_STRID_SIZE)
170 #define XIA_MAX_STRADDR_SIZE (1 + XIA_NODES_MAX * \
171 (XIA_MAX_STRXID_SIZE + XIA_OUTDEGREE_MAX * 2 + 2) + 1)
174 * Validating addresses
177 #define XIA_CHOSEN_EDGE 0x80
178 #define XIA_EMPTY_EDGE 0x7f
179 #define XIA_ENTRY_NODE_INDEX 0x7e
181 #define XIA_EMPTY_EDGES (XIA_EMPTY_EDGE << 24 | XIA_EMPTY_EDGE << 16 |\
182 XIA_EMPTY_EDGE << 8 | XIA_EMPTY_EDGE)
183 #define XIA_CHOSEN_EDGES (XIA_CHOSEN_EDGE << 24 | XIA_CHOSEN_EDGE << 16 |\
184 XIA_CHOSEN_EDGE << 8 | XIA_CHOSEN_EDGE)
187 is_edge_chosen(guint8 e)
189 return e & XIA_CHOSEN_EDGE;
193 is_any_edge_chosen(const struct xia_row *row)
195 return row->s_edge.i & XIA_CHOSEN_EDGES;
199 is_empty_edge(guint8 e)
201 return (e & XIA_EMPTY_EDGE) == XIA_EMPTY_EDGE;
205 xia_is_nat(xid_type_t ty)
207 return ty == XIDTYPE_NAT;
211 xia_are_edges_valid(const struct xia_row *row,
212 guint8 node, guint8 num_node, guint32 *pvisited)
215 guint32 all_edges, bits;
218 if (is_any_edge_chosen(row)) {
219 /* Since at least an edge of last_node has already
220 * been chosen, the address is corrupted.
222 return -XIAEADDR_CHOSEN_EDGE;
225 edge = row->s_edge.a;
226 all_edges = g_ntohl(row->s_edge.i);
228 for (i = 0; i < XIA_OUTDEGREE_MAX; i++, edge++) {
231 if (e == XIA_EMPTY_EDGE) {
232 if ((all_edges & bits) !=
233 (XIA_EMPTY_EDGES & bits))
234 return -XIAEADDR_EE_MISPLACED;
237 } else if (e >= num_node) {
238 return -XIAEADDR_EDGE_OUT_RANGE;
239 } else if (node < (num_node - 1) && e <= node) {
240 /* Notice that if (node == XIA_ENTRY_NODE_INDEX)
241 * it still works fine because XIA_ENTRY_NODE_INDEX
242 * is greater than (num_node - 1).
244 return -XIAEADDR_NOT_TOPOLOGICAL;
253 xia_test_addr(const struct xia_addr *addr)
259 /* Test that XIDTYPE_NAT is present only on last rows. */
261 for (i = 0; i < XIA_NODES_MAX; i++) {
263 ty = addr->s_row[i].s_xid.xid_type;
266 return -XIAEADDR_NAT_MISPLACED;
267 } else if (xia_is_nat(ty)) {
272 /* n = number of nodes from here. */
274 /* Test edges are well formed. */
275 for (i = 0; i < n; i++) {
277 rc = xia_are_edges_valid(&addr->s_row[i], i, n, &visited);
283 /* Test entry point is present. Notice that it's just a
284 * friendlier error since it's also XIAEADDR_MULTI_COMPONENTS.
287 all_edges = addr->s_row[n - 1].s_edge.i;
288 if (all_edges == XIA_EMPTY_EDGES)
289 return -XIAEADDR_NO_ENTRY;
291 if (visited != ((1U << n) - 1))
292 return -XIAEADDR_MULTI_COMPONENTS;
299 * Printing addresses out
302 #define INDEX_BASE 36
305 edge_to_char(guint8 e)
307 const gchar *ch_edge = "0123456789abcdefghijklmnopqrstuvwxyz";
308 e &= ~XIA_CHOSEN_EDGE;
311 else if (is_empty_edge(e))
318 add_edges_to_buf(gint valid, wmem_strbuf_t *buf, const guint8 *edges)
321 wmem_strbuf_append_c(buf, '-');
322 for (i = 0; i < XIA_OUTDEGREE_MAX; i++) {
323 if (valid && edges[i] == XIA_EMPTY_EDGE)
326 if (is_edge_chosen(edges[i]))
327 wmem_strbuf_append_c(buf, '>');
329 wmem_strbuf_append_c(buf, edge_to_char(edges[i]));
334 add_type_to_buf(xid_type_t ty, wmem_strbuf_t *buf)
336 const gchar *xid_name;
337 gsize buflen = wmem_strbuf_get_len(buf);
339 if (XIA_MAX_STRADDR_SIZE - buflen - 1 < MAX_PPAL_NAME_SIZE)
342 xid_name = try_val_to_str(ty, xidtype_vals);
344 wmem_strbuf_append_printf(buf, "%s-", xid_name);
346 wmem_strbuf_append_printf(buf, "0x%x-", ty);
350 add_id_to_buf(const struct xia_xid *src, wmem_strbuf_t *buf)
352 wmem_strbuf_append_printf(buf, "%08x%08x%08x%08x%08x",
360 /* xia_ntop - convert an XIA address to a string.
361 * @src can be ill-formed, but xia_ntop won't report an error and will return
362 * a string that approximates that ill-formed address.
365 xia_ntop(const struct xia_addr *src, wmem_strbuf_t *buf)
369 valid = xia_test_addr(src) >= 1;
371 wmem_strbuf_append_c(buf, '!');
373 for (i = 0; i < XIA_NODES_MAX; i++) {
374 const struct xia_row *row = &src->s_row[i];
376 if (xia_is_nat(row->s_xid.xid_type))
380 wmem_strbuf_append(buf, ":\n");
382 /* Add the type, ID, and edges for this node. */
383 add_type_to_buf(row->s_xid.xid_type, buf);
384 add_id_to_buf(&row->s_xid, buf);
385 add_edges_to_buf(valid, buf, row->s_edge.a);
395 #define XIPH_MIN_LEN 36
396 #define ETHERTYPE_XIP 0xC0DE
397 #define XIA_NEXT_HEADER_DATA 0
399 /* Offsets of XIP fields in bytes. */
410 construct_dag(tvbuff_t *tvb, proto_tree *xip_tree,
411 const gint ett, const gint hf, const gint hf_entry,
412 const guint8 num_nodes, guint8 offset)
414 proto_tree *dag_tree;
418 const gchar *dag_str;
420 guint8 dag_offset = offset;
422 ti = proto_tree_add_item(xip_tree, hf, tvb, offset,
423 num_nodes * XIA_NODE_SIZE, ENC_BIG_ENDIAN);
425 buf = wmem_strbuf_sized_new(wmem_packet_scope(),
426 XIA_MAX_STRADDR_SIZE, XIA_MAX_STRADDR_SIZE);
428 dag_tree = proto_item_add_subtree(ti, ett);
430 memset(&dag, 0, sizeof(dag));
431 for (i = 0; i < num_nodes; i++) {
432 struct xia_row *row = &dag.s_row[i];
434 row->s_xid.xid_type = tvb_get_ntohl(tvb, offset);
435 offset += XIA_TYPE_SIZE;
437 /* Process the ID 32 bits at a time. */
438 for (j = 0; j < XIA_XID_SIZE / XIA_XID_CHUNK_SIZE; j++) {
439 row->s_xid.xid_id[j] = tvb_get_ntohl(tvb, offset);
440 offset += XIA_XID_CHUNK_SIZE;
443 /* Need to process the edges byte-by-byte,
444 * so keep the bytes in network order.
446 tvb_memcpy(tvb, row->s_edge.a, offset, XIA_EDGES_SIZE);
447 offset += XIA_EDGES_SIZE;
451 dag_str = wmem_strbuf_get_str(buf);
452 proto_tree_add_string_format(dag_tree, hf_entry, tvb, dag_offset,
453 XIA_NODE_SIZE * num_nodes, dag_str, "%s", dag_str);
457 display_xip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
459 proto_tree *xip_tree = NULL;
461 proto_item *ti = NULL;
462 proto_item *payload_ti = NULL;
463 proto_item *next_ti = NULL;
464 proto_item *num_ti = NULL;
468 guint16 xiph_len, payload_len;
469 guint8 num_dst_nodes, num_src_nodes, last_node,
470 next_header, next_header_offset;
472 num_dst_nodes = tvb_get_guint8(tvb, XIPH_NDST);
473 num_src_nodes = tvb_get_guint8(tvb, XIPH_NSRC);
474 xiph_len = 8 + (XIA_NODE_SIZE * num_dst_nodes) +
475 (XIA_NODE_SIZE * num_src_nodes);
477 /* Construct protocol tree. */
478 ti = proto_tree_add_item(tree, proto_xip, tvb, 0, xiph_len, ENC_NA);
479 xip_tree = proto_item_add_subtree(ti, ett_xip_tree);
481 /* Add XIP version. */
482 proto_tree_add_item(xip_tree, hf_xip_version, tvb,
483 XIPH_VERS, 1, ENC_BIG_ENDIAN);
485 /* Add XIP next header. */
486 next_ti = proto_tree_add_item(xip_tree, hf_xip_next_hdr, tvb,
487 XIPH_NXTH, 1, ENC_BIG_ENDIAN);
489 /* Add XIP payload length. */
490 payload_len = tvb_get_ntohs(tvb, XIPH_PLEN);
491 payload_ti = proto_tree_add_uint_format(xip_tree, hf_xip_payload_len,
492 tvb, XIPH_PLEN, 2, payload_len, "Payload Length: %u bytes",
494 if (tvb_captured_length_remaining(tvb, xiph_len) != payload_len)
495 expert_add_info_format(pinfo, payload_ti, &ei_xip_invalid_len,
496 "Payload length field (%d bytes) does not match actual payload length (%d bytes)",
497 payload_len, tvb_captured_length_remaining(tvb, xiph_len));
499 /* Add XIP hop limit. */
500 proto_tree_add_item(xip_tree, hf_xip_hop_limit, tvb,
501 XIPH_HOPL, 1, ENC_BIG_ENDIAN);
503 /* Add XIP number of destination DAG nodes. */
504 num_ti = proto_tree_add_item(xip_tree, hf_xip_num_dst, tvb,
505 XIPH_NDST, 1, ENC_BIG_ENDIAN);
506 if (num_dst_nodes > XIA_NODES_MAX) {
507 expert_add_info_format(pinfo, num_ti, &ei_xip_bad_num_dst,
508 "The number of destination DAG nodes (%d) must be less than XIA_NODES_MAX (%d)",
509 num_dst_nodes, XIA_NODES_MAX);
510 num_dst_nodes = XIA_NODES_MAX;
513 /* Add XIP number of source DAG nodes. */
514 num_ti = proto_tree_add_item(xip_tree, hf_xip_num_src, tvb,
515 XIPH_NSRC, 1, ENC_BIG_ENDIAN);
516 if (num_src_nodes > XIA_NODES_MAX) {
517 expert_add_info_format(pinfo, num_ti, &ei_xip_bad_num_src,
518 "The number of source DAG nodes (%d) must be less than XIA_NODES_MAX (%d)",
519 num_src_nodes, XIA_NODES_MAX);
520 num_src_nodes = XIA_NODES_MAX;
523 /* Add XIP last node. */
524 last_node = tvb_get_guint8(tvb, XIPH_LSTN);
525 proto_tree_add_uint_format_value(xip_tree, hf_xip_last_node, tvb,
526 XIPH_LSTN, 1, last_node, "%d%s", last_node,
527 last_node == XIA_ENTRY_NODE_INDEX ? " (entry node)" : "");
529 /* Construct Destination DAG subtree. */
530 if (num_dst_nodes > 0)
531 construct_dag(tvb, xip_tree, ett_xip_ddag,
532 hf_xip_dst_dag, hf_xip_dst_dag_entry,
533 num_dst_nodes, XIPH_DSTD);
535 /* Construct Source DAG subtree. */
536 if (num_src_nodes > 0)
537 construct_dag(tvb, xip_tree, ett_xip_sdag,
538 hf_xip_src_dag, hf_xip_src_dag_entry,
540 XIPH_DSTD + num_dst_nodes * XIA_NODE_SIZE);
542 next_header_offset = XIPH_DSTD + XIA_NODE_SIZE *
543 (num_dst_nodes + num_src_nodes);
545 next_header = tvb_get_guint8(tvb, XIPH_NXTH);
546 switch (next_header) {
547 case XIA_NEXT_HEADER_DATA:
548 next_tvb = tvb_new_subset(tvb, next_header_offset, -1, -1);
549 call_dissector(data_handle, next_tvb, pinfo, tree);
552 expert_add_info_format(pinfo, next_ti, &ei_xip_next_header,
553 "Unrecognized next header type: 0x%02x", next_header);
559 dissect_xip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
562 /* Not large enough to be valid XIP packet. */
563 if (tvb_reported_length(tvb) < XIPH_MIN_LEN)
566 col_set_str(pinfo->cinfo, COL_PROTOCOL, "XIP");
567 col_set_str(pinfo->cinfo, COL_INFO, "XIP Packet");
569 display_xip(tvb, pinfo, tree);
570 return tvb_captured_length(tvb);
574 proto_register_xip(void)
576 static hf_register_info hf[] = {
581 { "Version", "xip.version", FT_UINT8,
582 BASE_DEC, NULL, 0x0, NULL, HFILL }},
585 { "Next Header", "xip.next_hdr", FT_UINT8,
586 BASE_DEC, NULL, 0x0, NULL, HFILL }},
588 { &hf_xip_payload_len,
589 { "Payload Length", "xip.payload_len", FT_UINT16,
590 BASE_DEC, NULL, 0x0, NULL, HFILL }},
593 { "Hop Limit", "xip.hop_limit", FT_UINT8,
594 BASE_DEC, NULL, 0x0, NULL, HFILL }},
597 { "Number of Destination Nodes", "xip.num_dst", FT_UINT8,
598 BASE_DEC, NULL, 0x0, NULL, HFILL }},
601 { "Number of Source Nodes", "xip.num_src", FT_UINT8,
602 BASE_DEC, NULL, 0x0, NULL, HFILL }},
605 { "Last Node", "xip.last_node", FT_UINT8,
606 BASE_DEC, NULL, 0x0, NULL, HFILL }},
609 { "Destination DAG", "xip.dst_dag", FT_NONE,
610 BASE_NONE, NULL, 0x0, NULL, HFILL }},
612 { &hf_xip_dst_dag_entry,
613 { "Destination DAG Entry", "xip.dst_dag_entry", FT_STRING,
614 BASE_NONE, NULL, 0x0, NULL, HFILL }},
617 { "Source DAG", "xip.src_dag", FT_NONE,
618 BASE_NONE, NULL, 0x0, NULL, HFILL }},
620 { &hf_xip_src_dag_entry,
621 { "Source DAG Entry", "xip.src_dag_entry", FT_STRING,
622 BASE_NONE, NULL, 0x0, NULL, HFILL }}
625 static gint *ett[] = {
631 static ei_register_info ei[] = {
632 { &ei_xip_invalid_len,
633 { "xip.invalid.len", PI_MALFORMED, PI_ERROR,
634 "Invalid length", EXPFILL }},
636 { &ei_xip_next_header,
637 { "xip.next.header", PI_MALFORMED, PI_ERROR,
638 "Invalid next header", EXPFILL }},
640 { &ei_xip_bad_num_dst,
641 { "xip.bad_num_dst", PI_MALFORMED, PI_ERROR,
642 "Invalid number of destination DAG nodes", EXPFILL }},
644 { &ei_xip_bad_num_src,
645 { "xip.bad_num_src", PI_MALFORMED, PI_ERROR,
646 "Invalid number of source DAG nodes", EXPFILL }}
649 expert_module_t* expert_xip;
651 proto_xip = proto_register_protocol(
652 "eXpressive Internet Protocol",
656 new_register_dissector("xip", dissect_xip, proto_xip);
657 proto_register_field_array(proto_xip, hf, array_length(hf));
658 proto_register_subtree_array(ett, array_length(ett));
660 expert_xip = expert_register_protocol(proto_xip);
661 expert_register_field_array(expert_xip, ei, array_length(ei));
665 proto_reg_handoff_xip(void)
667 dissector_handle_t xip_handle;
669 xip_handle = new_create_dissector_handle(dissect_xip, proto_xip);
670 dissector_add_uint("ethertype", ETHERTYPE_XIP, xip_handle);
672 data_handle = find_dissector("data");
676 * Editor modelines - http://www.wireshark.org/tools/modelines.html
681 * indent-tabs-mode: t
684 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
685 * :indentSize=8:tabSize=8:noTabs=false: