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 #include "netdissect.h"
36 enum af_vsockmon_transport
{
37 AF_VSOCK_TRANSPORT_UNKNOWN
= 0,
38 AF_VSOCK_TRANSPORT_NO_INFO
= 1, /* No transport information */
39 AF_VSOCK_TRANSPORT_VIRTIO
= 2, /* Virtio transport header */
42 static const struct tok vsock_transport
[] = {
43 {AF_VSOCK_TRANSPORT_UNKNOWN
, "UNKNOWN"},
44 {AF_VSOCK_TRANSPORT_NO_INFO
, "NO_INFO"},
45 {AF_VSOCK_TRANSPORT_VIRTIO
, "VIRTIO"},
50 AF_VSOCK_OP_UNKNOWN
= 0,
51 AF_VSOCK_OP_CONNECT
= 1,
52 AF_VSOCK_OP_DISCONNECT
= 2,
53 AF_VSOCK_OP_CONTROL
= 3,
54 AF_VSOCK_OP_PAYLOAD
= 4,
57 static const struct tok vsock_op
[] = {
58 {AF_VSOCK_OP_UNKNOWN
, "UNKNOWN"},
59 {AF_VSOCK_OP_CONNECT
, "CONNECT"},
60 {AF_VSOCK_OP_DISCONNECT
, "DISCONNECT"},
61 {AF_VSOCK_OP_CONTROL
, "CONTROL"},
62 {AF_VSOCK_OP_PAYLOAD
, "PAYLOAD"},
66 enum virtio_vsock_type
{
67 VIRTIO_VSOCK_TYPE_STREAM
= 1,
70 static const struct tok virtio_type
[] = {
71 {VIRTIO_VSOCK_TYPE_STREAM
, "STREAM"},
75 enum virtio_vsock_op
{
76 VIRTIO_VSOCK_OP_INVALID
= 0,
77 VIRTIO_VSOCK_OP_REQUEST
= 1,
78 VIRTIO_VSOCK_OP_RESPONSE
= 2,
79 VIRTIO_VSOCK_OP_RST
= 3,
80 VIRTIO_VSOCK_OP_SHUTDOWN
= 4,
81 VIRTIO_VSOCK_OP_RW
= 5,
82 VIRTIO_VSOCK_OP_CREDIT_UPDATE
= 6,
83 VIRTIO_VSOCK_OP_CREDIT_REQUEST
= 7,
86 static const struct tok virtio_op
[] = {
87 {VIRTIO_VSOCK_OP_INVALID
, "INVALID"},
88 {VIRTIO_VSOCK_OP_REQUEST
, "REQUEST"},
89 {VIRTIO_VSOCK_OP_RESPONSE
, "RESPONSE"},
90 {VIRTIO_VSOCK_OP_RST
, "RST"},
91 {VIRTIO_VSOCK_OP_SHUTDOWN
, "SHUTDOWN"},
92 {VIRTIO_VSOCK_OP_RW
, "RW"},
93 {VIRTIO_VSOCK_OP_CREDIT_UPDATE
, "CREDIT UPDATE"},
94 {VIRTIO_VSOCK_OP_CREDIT_REQUEST
, "CREDIT REQUEST"},
98 /* All fields are little-endian */
100 struct virtio_vsock_hdr
{
103 nd_uint32_t src_port
;
104 nd_uint32_t dst_port
;
106 nd_uint16_t type
; /* enum virtio_vsock_type */
107 nd_uint16_t op
; /* enum virtio_vsock_op */
109 nd_uint32_t buf_alloc
;
113 struct af_vsockmon_hdr
{
116 nd_uint32_t src_port
;
117 nd_uint32_t dst_port
;
118 nd_uint16_t op
; /* enum af_vsockmon_op */
119 nd_uint16_t transport
; /* enum af_vosckmon_transport */
120 nd_uint16_t len
; /* size of transport header */
121 nd_uint8_t reserved
[2];
125 vsock_virtio_hdr_print(netdissect_options
*ndo
, const struct virtio_vsock_hdr
*hdr
)
130 u32_v
= GET_LE_U_4(hdr
->len
);
131 ND_PRINT("len %u", u32_v
);
133 u16_v
= GET_LE_U_2(hdr
->type
);
134 ND_PRINT(", type %s",
135 tok2str(virtio_type
, "Invalid type (%hu)", u16_v
));
137 u16_v
= GET_LE_U_2(hdr
->op
);
139 tok2str(virtio_op
, "Invalid op (%hu)", u16_v
));
141 u32_v
= GET_LE_U_4(hdr
->flags
);
142 ND_PRINT(", flags %x", u32_v
);
144 u32_v
= GET_LE_U_4(hdr
->buf_alloc
);
145 ND_PRINT(", buf_alloc %u", u32_v
);
147 u32_v
= GET_LE_U_4(hdr
->fwd_cnt
);
148 ND_PRINT(", fwd_cnt %u", u32_v
);
152 vsock_transport_hdr_size(uint16_t transport
)
155 case AF_VSOCK_TRANSPORT_VIRTIO
:
156 return sizeof(struct virtio_vsock_hdr
);
162 /* Returns 0 on success, -1 on truncation */
164 vsock_transport_hdr_print(netdissect_options
*ndo
, uint16_t transport
,
165 const u_char
*p
, const u_int len
)
167 size_t transport_size
= vsock_transport_hdr_size(transport
);
170 if (len
< sizeof(struct af_vsockmon_hdr
) + transport_size
) {
174 hdr
= p
+ sizeof(struct af_vsockmon_hdr
);
176 case AF_VSOCK_TRANSPORT_VIRTIO
:
178 vsock_virtio_hdr_print(ndo
, hdr
);
188 vsock_hdr_print(netdissect_options
*ndo
, const u_char
*p
, const u_int len
)
190 const struct af_vsockmon_hdr
*hdr
= (const struct af_vsockmon_hdr
*)p
;
191 uint16_t hdr_transport
, hdr_op
;
192 uint32_t hdr_src_port
, hdr_dst_port
;
193 uint64_t hdr_src_cid
, hdr_dst_cid
;
194 size_t total_hdr_size
;
197 hdr_transport
= GET_LE_U_2(hdr
->transport
);
199 tok2str(vsock_transport
, "Invalid transport (%u)",
202 /* If verbose level is more than 0 print transport details */
203 if (ndo
->ndo_vflag
) {
204 ret
= vsock_transport_hdr_print(ndo
, hdr_transport
, p
, len
);
210 hdr_src_cid
= GET_LE_U_8(hdr
->src_cid
);
211 hdr_dst_cid
= GET_LE_U_8(hdr
->dst_cid
);
212 hdr_src_port
= GET_LE_U_4(hdr
->src_port
);
213 hdr_dst_port
= GET_LE_U_4(hdr
->dst_port
);
214 hdr_op
= GET_LE_U_2(hdr
->op
);
215 ND_PRINT("%" PRIu64
".%u > %" PRIu64
".%u %s, length %u",
216 hdr_src_cid
, hdr_src_port
,
217 hdr_dst_cid
, hdr_dst_port
,
218 tok2str(vsock_op
, " invalid op (%u)", hdr_op
),
224 /* If debug level is more than 1 print payload contents */
225 total_hdr_size
= sizeof(struct af_vsockmon_hdr
) +
226 vsock_transport_hdr_size(hdr_transport
);
227 if (ndo
->ndo_vflag
> 1 && hdr_op
== AF_VSOCK_OP_PAYLOAD
) {
228 if (len
> total_hdr_size
) {
229 const u_char
*payload
= p
+ total_hdr_size
;
232 print_unknown_data(ndo
, payload
, "\t",
233 len
- total_hdr_size
);
244 vsock_if_print(netdissect_options
*ndo
, const struct pcap_pkthdr
*h
,
247 u_int len
= h
->caplen
;
249 ndo
->ndo_protocol
= "vsock";
251 if (len
< sizeof(struct af_vsockmon_hdr
))
254 vsock_hdr_print(ndo
, cp
, len
);