2 * Copyright (c) 2016 Gerard Garcia <nouboh@gmail.com>
3 * Copyright (c) 2017 Red Hat, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
15 * 3. The names of the authors may not be used to endorse or promote
16 * products derived from this software without specific prior
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 /* \summary: Linux vsock printer */
30 #include "netdissect-stdinc.h"
33 #define ND_LONGJMP_FROM_TCHECK
34 #include "netdissect.h"
37 enum af_vsockmon_transport
{
38 AF_VSOCK_TRANSPORT_UNKNOWN
= 0,
39 AF_VSOCK_TRANSPORT_NO_INFO
= 1, /* No transport information */
40 AF_VSOCK_TRANSPORT_VIRTIO
= 2, /* Virtio transport header */
43 static const struct tok vsock_transport
[] = {
44 {AF_VSOCK_TRANSPORT_UNKNOWN
, "UNKNOWN"},
45 {AF_VSOCK_TRANSPORT_NO_INFO
, "NO_INFO"},
46 {AF_VSOCK_TRANSPORT_VIRTIO
, "VIRTIO"},
51 AF_VSOCK_OP_UNKNOWN
= 0,
52 AF_VSOCK_OP_CONNECT
= 1,
53 AF_VSOCK_OP_DISCONNECT
= 2,
54 AF_VSOCK_OP_CONTROL
= 3,
55 AF_VSOCK_OP_PAYLOAD
= 4,
58 static const struct tok vsock_op
[] = {
59 {AF_VSOCK_OP_UNKNOWN
, "UNKNOWN"},
60 {AF_VSOCK_OP_CONNECT
, "CONNECT"},
61 {AF_VSOCK_OP_DISCONNECT
, "DISCONNECT"},
62 {AF_VSOCK_OP_CONTROL
, "CONTROL"},
63 {AF_VSOCK_OP_PAYLOAD
, "PAYLOAD"},
67 enum virtio_vsock_type
{
68 VIRTIO_VSOCK_TYPE_STREAM
= 1,
71 static const struct tok virtio_type
[] = {
72 {VIRTIO_VSOCK_TYPE_STREAM
, "STREAM"},
76 enum virtio_vsock_op
{
77 VIRTIO_VSOCK_OP_INVALID
= 0,
78 VIRTIO_VSOCK_OP_REQUEST
= 1,
79 VIRTIO_VSOCK_OP_RESPONSE
= 2,
80 VIRTIO_VSOCK_OP_RST
= 3,
81 VIRTIO_VSOCK_OP_SHUTDOWN
= 4,
82 VIRTIO_VSOCK_OP_RW
= 5,
83 VIRTIO_VSOCK_OP_CREDIT_UPDATE
= 6,
84 VIRTIO_VSOCK_OP_CREDIT_REQUEST
= 7,
87 static const struct tok virtio_op
[] = {
88 {VIRTIO_VSOCK_OP_INVALID
, "INVALID"},
89 {VIRTIO_VSOCK_OP_REQUEST
, "REQUEST"},
90 {VIRTIO_VSOCK_OP_RESPONSE
, "RESPONSE"},
91 {VIRTIO_VSOCK_OP_RST
, "RST"},
92 {VIRTIO_VSOCK_OP_SHUTDOWN
, "SHUTDOWN"},
93 {VIRTIO_VSOCK_OP_RW
, "RW"},
94 {VIRTIO_VSOCK_OP_CREDIT_UPDATE
, "CREDIT UPDATE"},
95 {VIRTIO_VSOCK_OP_CREDIT_REQUEST
, "CREDIT REQUEST"},
99 /* All fields are little-endian */
101 struct virtio_vsock_hdr
{
104 nd_uint32_t src_port
;
105 nd_uint32_t dst_port
;
107 nd_uint16_t type
; /* enum virtio_vsock_type */
108 nd_uint16_t op
; /* enum virtio_vsock_op */
110 nd_uint32_t buf_alloc
;
114 struct af_vsockmon_hdr
{
117 nd_uint32_t src_port
;
118 nd_uint32_t dst_port
;
119 nd_uint16_t op
; /* enum af_vsockmon_op */
120 nd_uint16_t transport
; /* enum af_vosckmon_transport */
121 nd_uint16_t len
; /* size of transport header */
122 nd_uint8_t reserved
[2];
126 vsock_virtio_hdr_print(netdissect_options
*ndo
, const struct virtio_vsock_hdr
*hdr
)
131 u32_v
= GET_LE_U_4(hdr
->len
);
132 ND_PRINT("len %u", u32_v
);
134 u16_v
= GET_LE_U_2(hdr
->type
);
135 ND_PRINT(", type %s",
136 tok2str(virtio_type
, "Invalid type (%hu)", u16_v
));
138 u16_v
= GET_LE_U_2(hdr
->op
);
140 tok2str(virtio_op
, "Invalid op (%hu)", u16_v
));
142 u32_v
= GET_LE_U_4(hdr
->flags
);
143 ND_PRINT(", flags %x", u32_v
);
145 u32_v
= GET_LE_U_4(hdr
->buf_alloc
);
146 ND_PRINT(", buf_alloc %u", u32_v
);
148 u32_v
= GET_LE_U_4(hdr
->fwd_cnt
);
149 ND_PRINT(", fwd_cnt %u", u32_v
);
153 * This size had better fit in a u_int.
156 vsock_transport_hdr_size(uint16_t transport
)
159 case AF_VSOCK_TRANSPORT_VIRTIO
:
160 return (u_int
)sizeof(struct virtio_vsock_hdr
);
166 /* Returns 0 on success, -1 on truncation */
168 vsock_transport_hdr_print(netdissect_options
*ndo
, uint16_t transport
,
169 const u_char
*p
, const u_int caplen
)
171 u_int transport_size
= vsock_transport_hdr_size(transport
);
174 if (caplen
< sizeof(struct af_vsockmon_hdr
) + transport_size
) {
178 hdr
= p
+ sizeof(struct af_vsockmon_hdr
);
180 case AF_VSOCK_TRANSPORT_VIRTIO
:
182 vsock_virtio_hdr_print(ndo
, hdr
);
192 vsock_hdr_print(netdissect_options
*ndo
, const u_char
*p
, const u_int caplen
)
194 const struct af_vsockmon_hdr
*hdr
= (const struct af_vsockmon_hdr
*)p
;
195 uint16_t hdr_transport
, hdr_op
;
196 uint32_t hdr_src_port
, hdr_dst_port
;
197 uint64_t hdr_src_cid
, hdr_dst_cid
;
198 u_int total_hdr_size
;
201 hdr_transport
= GET_LE_U_2(hdr
->transport
);
203 tok2str(vsock_transport
, "Invalid transport (%u)",
206 /* If verbose level is more than 0 print transport details */
207 if (ndo
->ndo_vflag
) {
208 ret
= vsock_transport_hdr_print(ndo
, hdr_transport
, p
, caplen
);
214 hdr_src_cid
= GET_LE_U_8(hdr
->src_cid
);
215 hdr_dst_cid
= GET_LE_U_8(hdr
->dst_cid
);
216 hdr_src_port
= GET_LE_U_4(hdr
->src_port
);
217 hdr_dst_port
= GET_LE_U_4(hdr
->dst_port
);
218 hdr_op
= GET_LE_U_2(hdr
->op
);
219 ND_PRINT("%" PRIu64
".%u > %" PRIu64
".%u %s, length %u",
220 hdr_src_cid
, hdr_src_port
,
221 hdr_dst_cid
, hdr_dst_port
,
222 tok2str(vsock_op
, " invalid op (%u)", hdr_op
),
228 /* If debug level is more than 1 print payload contents */
229 /* This size had better fit in a u_int */
230 total_hdr_size
= (u_int
)sizeof(struct af_vsockmon_hdr
) +
231 vsock_transport_hdr_size(hdr_transport
);
232 if (ndo
->ndo_vflag
> 1 && hdr_op
== AF_VSOCK_OP_PAYLOAD
) {
233 if (caplen
> total_hdr_size
) {
234 const u_char
*payload
= p
+ total_hdr_size
;
237 print_unknown_data(ndo
, payload
, "\t",
238 caplen
- total_hdr_size
);
249 vsock_if_print(netdissect_options
*ndo
, const struct pcap_pkthdr
*h
,
252 ndo
->ndo_protocol
= "vsock";
254 ND_TCHECK_LEN(cp
, sizeof(struct af_vsockmon_hdr
));
255 ndo
->ndo_ll_hdr_len
+= sizeof(struct af_vsockmon_hdr
);
256 vsock_hdr_print(ndo
, cp
, h
->caplen
);