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 #define ND_LONGJMP_FROM_TCHECK
32 #include "netdissect.h"
35 enum af_vsockmon_transport
{
36 AF_VSOCK_TRANSPORT_UNKNOWN
= 0,
37 AF_VSOCK_TRANSPORT_NO_INFO
= 1, /* No transport information */
38 AF_VSOCK_TRANSPORT_VIRTIO
= 2, /* Virtio transport header */
41 static const struct tok vsock_transport
[] = {
42 {AF_VSOCK_TRANSPORT_UNKNOWN
, "UNKNOWN"},
43 {AF_VSOCK_TRANSPORT_NO_INFO
, "NO_INFO"},
44 {AF_VSOCK_TRANSPORT_VIRTIO
, "VIRTIO"},
49 AF_VSOCK_OP_UNKNOWN
= 0,
50 AF_VSOCK_OP_CONNECT
= 1,
51 AF_VSOCK_OP_DISCONNECT
= 2,
52 AF_VSOCK_OP_CONTROL
= 3,
53 AF_VSOCK_OP_PAYLOAD
= 4,
56 static const struct tok vsock_op
[] = {
57 {AF_VSOCK_OP_UNKNOWN
, "UNKNOWN"},
58 {AF_VSOCK_OP_CONNECT
, "CONNECT"},
59 {AF_VSOCK_OP_DISCONNECT
, "DISCONNECT"},
60 {AF_VSOCK_OP_CONTROL
, "CONTROL"},
61 {AF_VSOCK_OP_PAYLOAD
, "PAYLOAD"},
65 enum virtio_vsock_type
{
66 VIRTIO_VSOCK_TYPE_STREAM
= 1,
69 static const struct tok virtio_type
[] = {
70 {VIRTIO_VSOCK_TYPE_STREAM
, "STREAM"},
74 enum virtio_vsock_op
{
75 VIRTIO_VSOCK_OP_INVALID
= 0,
76 VIRTIO_VSOCK_OP_REQUEST
= 1,
77 VIRTIO_VSOCK_OP_RESPONSE
= 2,
78 VIRTIO_VSOCK_OP_RST
= 3,
79 VIRTIO_VSOCK_OP_SHUTDOWN
= 4,
80 VIRTIO_VSOCK_OP_RW
= 5,
81 VIRTIO_VSOCK_OP_CREDIT_UPDATE
= 6,
82 VIRTIO_VSOCK_OP_CREDIT_REQUEST
= 7,
85 static const struct tok virtio_op
[] = {
86 {VIRTIO_VSOCK_OP_INVALID
, "INVALID"},
87 {VIRTIO_VSOCK_OP_REQUEST
, "REQUEST"},
88 {VIRTIO_VSOCK_OP_RESPONSE
, "RESPONSE"},
89 {VIRTIO_VSOCK_OP_RST
, "RST"},
90 {VIRTIO_VSOCK_OP_SHUTDOWN
, "SHUTDOWN"},
91 {VIRTIO_VSOCK_OP_RW
, "RW"},
92 {VIRTIO_VSOCK_OP_CREDIT_UPDATE
, "CREDIT UPDATE"},
93 {VIRTIO_VSOCK_OP_CREDIT_REQUEST
, "CREDIT REQUEST"},
97 /* All fields are little-endian */
99 struct virtio_vsock_hdr
{
102 nd_uint32_t src_port
;
103 nd_uint32_t dst_port
;
105 nd_uint16_t type
; /* enum virtio_vsock_type */
106 nd_uint16_t op
; /* enum virtio_vsock_op */
108 nd_uint32_t buf_alloc
;
112 struct af_vsockmon_hdr
{
115 nd_uint32_t src_port
;
116 nd_uint32_t dst_port
;
117 nd_uint16_t op
; /* enum af_vsockmon_op */
118 nd_uint16_t transport
; /* enum af_vosckmon_transport */
119 nd_uint16_t len
; /* size of transport header */
120 nd_uint8_t reserved
[2];
124 vsock_virtio_hdr_print(netdissect_options
*ndo
, const struct virtio_vsock_hdr
*hdr
)
129 u32_v
= GET_LE_U_4(hdr
->len
);
130 ND_PRINT("len %u", u32_v
);
132 u16_v
= GET_LE_U_2(hdr
->type
);
133 ND_PRINT(", type %s",
134 tok2str(virtio_type
, "Invalid type (%hu)", u16_v
));
136 u16_v
= GET_LE_U_2(hdr
->op
);
138 tok2str(virtio_op
, "Invalid op (%hu)", u16_v
));
140 u32_v
= GET_LE_U_4(hdr
->flags
);
141 ND_PRINT(", flags %x", u32_v
);
143 u32_v
= GET_LE_U_4(hdr
->buf_alloc
);
144 ND_PRINT(", buf_alloc %u", u32_v
);
146 u32_v
= GET_LE_U_4(hdr
->fwd_cnt
);
147 ND_PRINT(", fwd_cnt %u", u32_v
);
151 * This size had better fit in a u_int.
154 vsock_transport_hdr_size(uint16_t transport
)
157 case AF_VSOCK_TRANSPORT_VIRTIO
:
158 return (u_int
)sizeof(struct virtio_vsock_hdr
);
164 /* Returns 0 on success, -1 on truncation */
166 vsock_transport_hdr_print(netdissect_options
*ndo
, uint16_t transport
,
167 const u_char
*p
, const u_int caplen
)
169 u_int transport_size
= vsock_transport_hdr_size(transport
);
172 if (caplen
< sizeof(struct af_vsockmon_hdr
) + transport_size
) {
176 hdr
= p
+ sizeof(struct af_vsockmon_hdr
);
178 case AF_VSOCK_TRANSPORT_VIRTIO
:
180 vsock_virtio_hdr_print(ndo
, hdr
);
190 vsock_hdr_print(netdissect_options
*ndo
, const u_char
*p
, const u_int caplen
)
192 const struct af_vsockmon_hdr
*hdr
= (const struct af_vsockmon_hdr
*)p
;
193 uint16_t hdr_transport
, hdr_op
;
194 uint32_t hdr_src_port
, hdr_dst_port
;
195 uint64_t hdr_src_cid
, hdr_dst_cid
;
196 u_int total_hdr_size
;
199 hdr_transport
= GET_LE_U_2(hdr
->transport
);
201 tok2str(vsock_transport
, "Invalid transport (%u)",
204 /* If verbose level is more than 0 print transport details */
205 if (ndo
->ndo_vflag
) {
206 ret
= vsock_transport_hdr_print(ndo
, hdr_transport
, p
, caplen
);
212 hdr_src_cid
= GET_LE_U_8(hdr
->src_cid
);
213 hdr_dst_cid
= GET_LE_U_8(hdr
->dst_cid
);
214 hdr_src_port
= GET_LE_U_4(hdr
->src_port
);
215 hdr_dst_port
= GET_LE_U_4(hdr
->dst_port
);
216 hdr_op
= GET_LE_U_2(hdr
->op
);
217 ND_PRINT("%" PRIu64
".%u > %" PRIu64
".%u %s, length %u",
218 hdr_src_cid
, hdr_src_port
,
219 hdr_dst_cid
, hdr_dst_port
,
220 tok2str(vsock_op
, " invalid op (%u)", hdr_op
),
226 /* If debug level is more than 1 print payload contents */
227 /* This size had better fit in a u_int */
228 total_hdr_size
= (u_int
)sizeof(struct af_vsockmon_hdr
) +
229 vsock_transport_hdr_size(hdr_transport
);
230 if (ndo
->ndo_vflag
> 1 && hdr_op
== AF_VSOCK_OP_PAYLOAD
) {
231 if (caplen
> total_hdr_size
) {
232 const u_char
*payload
= p
+ total_hdr_size
;
235 print_unknown_data(ndo
, payload
, "\t",
236 caplen
- total_hdr_size
);
247 vsock_if_print(netdissect_options
*ndo
, const struct pcap_pkthdr
*h
,
250 ndo
->ndo_protocol
= "vsock";
252 ND_TCHECK_LEN(cp
, sizeof(struct af_vsockmon_hdr
));
253 ndo
->ndo_ll_hdr_len
+= sizeof(struct af_vsockmon_hdr
);
254 vsock_hdr_print(ndo
, cp
, h
->caplen
);