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 */
28 #include "netdissect-stdinc.h"
31 #include "netdissect.h"
34 enum af_vsockmon_transport
{
35 AF_VSOCK_TRANSPORT_UNKNOWN
= 0,
36 AF_VSOCK_TRANSPORT_NO_INFO
= 1, /* No transport information */
37 AF_VSOCK_TRANSPORT_VIRTIO
= 2, /* Virtio transport header */
40 static const struct tok vsock_transport
[] = {
41 {AF_VSOCK_TRANSPORT_UNKNOWN
, "UNKNOWN"},
42 {AF_VSOCK_TRANSPORT_NO_INFO
, "NO_INFO"},
43 {AF_VSOCK_TRANSPORT_VIRTIO
, "VIRTIO"},
48 AF_VSOCK_OP_UNKNOWN
= 0,
49 AF_VSOCK_OP_CONNECT
= 1,
50 AF_VSOCK_OP_DISCONNECT
= 2,
51 AF_VSOCK_OP_CONTROL
= 3,
52 AF_VSOCK_OP_PAYLOAD
= 4,
55 static const struct tok vsock_op
[] = {
56 {AF_VSOCK_OP_UNKNOWN
, "UNKNOWN"},
57 {AF_VSOCK_OP_CONNECT
, "CONNECT"},
58 {AF_VSOCK_OP_DISCONNECT
, "DISCONNECT"},
59 {AF_VSOCK_OP_CONTROL
, "CONTROL"},
60 {AF_VSOCK_OP_PAYLOAD
, "PAYLOAD"},
64 enum virtio_vsock_type
{
65 VIRTIO_VSOCK_TYPE_STREAM
= 1,
68 static const struct tok virtio_type
[] = {
69 {VIRTIO_VSOCK_TYPE_STREAM
, "STREAM"},
73 enum virtio_vsock_op
{
74 VIRTIO_VSOCK_OP_INVALID
= 0,
75 VIRTIO_VSOCK_OP_REQUEST
= 1,
76 VIRTIO_VSOCK_OP_RESPONSE
= 2,
77 VIRTIO_VSOCK_OP_RST
= 3,
78 VIRTIO_VSOCK_OP_SHUTDOWN
= 4,
79 VIRTIO_VSOCK_OP_RW
= 5,
80 VIRTIO_VSOCK_OP_CREDIT_UPDATE
= 6,
81 VIRTIO_VSOCK_OP_CREDIT_REQUEST
= 7,
84 static const struct tok virtio_op
[] = {
85 {VIRTIO_VSOCK_OP_INVALID
, "INVALID"},
86 {VIRTIO_VSOCK_OP_REQUEST
, "REQUEST"},
87 {VIRTIO_VSOCK_OP_RESPONSE
, "RESPONSE"},
88 {VIRTIO_VSOCK_OP_RST
, "RST"},
89 {VIRTIO_VSOCK_OP_SHUTDOWN
, "SHUTDOWN"},
90 {VIRTIO_VSOCK_OP_RW
, "RW"},
91 {VIRTIO_VSOCK_OP_CREDIT_UPDATE
, "CREDIT UPDATE"},
92 {VIRTIO_VSOCK_OP_CREDIT_REQUEST
, "CREDIT REQUEST"},
96 /* All fields are little-endian */
98 struct virtio_vsock_hdr
{
101 nd_uint32_t src_port
;
102 nd_uint32_t dst_port
;
104 nd_uint16_t type
; /* enum virtio_vsock_type */
105 nd_uint16_t op
; /* enum virtio_vsock_op */
107 nd_uint32_t buf_alloc
;
111 struct af_vsockmon_hdr
{
114 nd_uint32_t src_port
;
115 nd_uint32_t dst_port
;
116 nd_uint16_t op
; /* enum af_vsockmon_op */
117 nd_uint16_t transport
; /* enum af_vosckmon_transport */
118 nd_uint16_t len
; /* size of transport header */
119 nd_uint8_t reserved
[2];
123 vsock_virtio_hdr_print(netdissect_options
*ndo
, const struct virtio_vsock_hdr
*hdr
)
128 u32_v
= GET_LE_U_4(hdr
->len
);
129 ND_PRINT("len %u", u32_v
);
131 u16_v
= GET_LE_U_2(hdr
->type
);
132 ND_PRINT(", type %s",
133 tok2str(virtio_type
, "Invalid type (%hu)", u16_v
));
135 u16_v
= GET_LE_U_2(hdr
->op
);
137 tok2str(virtio_op
, "Invalid op (%hu)", u16_v
));
139 u32_v
= GET_LE_U_4(hdr
->flags
);
140 ND_PRINT(", flags %x", u32_v
);
142 u32_v
= GET_LE_U_4(hdr
->buf_alloc
);
143 ND_PRINT(", buf_alloc %u", u32_v
);
145 u32_v
= GET_LE_U_4(hdr
->fwd_cnt
);
146 ND_PRINT(", fwd_cnt %u", u32_v
);
150 * This size had better fit in a u_int.
153 vsock_transport_hdr_size(uint16_t transport
)
156 case AF_VSOCK_TRANSPORT_VIRTIO
:
157 return (u_int
)sizeof(struct virtio_vsock_hdr
);
163 /* Returns 0 on success, -1 on truncation */
165 vsock_transport_hdr_print(netdissect_options
*ndo
, uint16_t transport
,
166 const u_char
*p
, const u_int caplen
)
168 u_int transport_size
= vsock_transport_hdr_size(transport
);
171 if (caplen
< sizeof(struct af_vsockmon_hdr
) + transport_size
) {
175 hdr
= p
+ sizeof(struct af_vsockmon_hdr
);
177 case AF_VSOCK_TRANSPORT_VIRTIO
:
179 vsock_virtio_hdr_print(ndo
, hdr
);
189 vsock_hdr_print(netdissect_options
*ndo
, const u_char
*p
, const u_int caplen
)
191 const struct af_vsockmon_hdr
*hdr
= (const struct af_vsockmon_hdr
*)p
;
192 uint16_t hdr_transport
, hdr_op
;
193 uint32_t hdr_src_port
, hdr_dst_port
;
194 uint64_t hdr_src_cid
, hdr_dst_cid
;
195 u_int total_hdr_size
;
198 hdr_transport
= GET_LE_U_2(hdr
->transport
);
200 tok2str(vsock_transport
, "Invalid transport (%u)",
203 /* If verbose level is more than 0 print transport details */
204 if (ndo
->ndo_vflag
) {
205 ret
= vsock_transport_hdr_print(ndo
, hdr_transport
, p
, caplen
);
211 hdr_src_cid
= GET_LE_U_8(hdr
->src_cid
);
212 hdr_dst_cid
= GET_LE_U_8(hdr
->dst_cid
);
213 hdr_src_port
= GET_LE_U_4(hdr
->src_port
);
214 hdr_dst_port
= GET_LE_U_4(hdr
->dst_port
);
215 hdr_op
= GET_LE_U_2(hdr
->op
);
216 ND_PRINT("%" PRIu64
".%u > %" PRIu64
".%u %s, length %u",
217 hdr_src_cid
, hdr_src_port
,
218 hdr_dst_cid
, hdr_dst_port
,
219 tok2str(vsock_op
, " invalid op (%u)", hdr_op
),
225 /* If debug level is more than 1 print payload contents */
226 /* This size had better fit in a u_int */
227 total_hdr_size
= (u_int
)sizeof(struct af_vsockmon_hdr
) +
228 vsock_transport_hdr_size(hdr_transport
);
229 if (ndo
->ndo_vflag
> 1 && hdr_op
== AF_VSOCK_OP_PAYLOAD
) {
230 if (caplen
> total_hdr_size
) {
231 const u_char
*payload
= p
+ total_hdr_size
;
234 print_unknown_data(ndo
, payload
, "\t",
235 caplen
- total_hdr_size
);
246 vsock_if_print(netdissect_options
*ndo
, const struct pcap_pkthdr
*h
,
249 u_int caplen
= h
->caplen
;
251 ndo
->ndo_protocol
= "vsock";
253 if (caplen
< sizeof(struct af_vsockmon_hdr
)) {
255 ndo
->ndo_ll_hdr_len
+= caplen
;
258 ndo
->ndo_ll_hdr_len
+= sizeof(struct af_vsockmon_hdr
);
259 vsock_hdr_print(ndo
, cp
, caplen
);