usbip_network.c (5998B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 4 * 2005-2007 Takahiro Hirofuchi 5 */ 6 7#include <sys/socket.h> 8 9#include <string.h> 10 11#include <arpa/inet.h> 12#include <netdb.h> 13#include <netinet/tcp.h> 14#include <unistd.h> 15 16#ifdef HAVE_LIBWRAP 17#include <tcpd.h> 18#endif 19 20#include "usbip_common.h" 21#include "usbip_network.h" 22 23int usbip_port = 3240; 24char *usbip_port_string = "3240"; 25 26void usbip_setup_port_number(char *arg) 27{ 28 dbg("parsing port arg '%s'", arg); 29 char *end; 30 unsigned long int port = strtoul(arg, &end, 10); 31 32 if (end == arg) { 33 err("port: could not parse '%s' as a decimal integer", arg); 34 return; 35 } 36 37 if (*end != '\0') { 38 err("port: garbage at end of '%s'", arg); 39 return; 40 } 41 42 if (port > UINT16_MAX) { 43 err("port: %s too high (max=%d)", 44 arg, UINT16_MAX); 45 return; 46 } 47 48 usbip_port = port; 49 usbip_port_string = arg; 50 info("using port %d (\"%s\")", usbip_port, usbip_port_string); 51} 52 53uint32_t usbip_net_pack_uint32_t(int pack, uint32_t num) 54{ 55 uint32_t i; 56 57 if (pack) 58 i = htonl(num); 59 else 60 i = ntohl(num); 61 62 return i; 63} 64 65uint16_t usbip_net_pack_uint16_t(int pack, uint16_t num) 66{ 67 uint16_t i; 68 69 if (pack) 70 i = htons(num); 71 else 72 i = ntohs(num); 73 74 return i; 75} 76 77void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev) 78{ 79 udev->busnum = usbip_net_pack_uint32_t(pack, udev->busnum); 80 udev->devnum = usbip_net_pack_uint32_t(pack, udev->devnum); 81 udev->speed = usbip_net_pack_uint32_t(pack, udev->speed); 82 83 udev->idVendor = usbip_net_pack_uint16_t(pack, udev->idVendor); 84 udev->idProduct = usbip_net_pack_uint16_t(pack, udev->idProduct); 85 udev->bcdDevice = usbip_net_pack_uint16_t(pack, udev->bcdDevice); 86} 87 88void usbip_net_pack_usb_interface(int pack __attribute__((unused)), 89 struct usbip_usb_interface *udev 90 __attribute__((unused))) 91{ 92 /* uint8_t members need nothing */ 93} 94 95static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen, 96 int sending) 97{ 98 ssize_t nbytes; 99 ssize_t total = 0; 100 101 if (!bufflen) 102 return 0; 103 104 do { 105 if (sending) 106 nbytes = send(sockfd, buff, bufflen, 0); 107 else 108 nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL); 109 110 if (nbytes <= 0) 111 return -1; 112 113 buff = (void *)((intptr_t) buff + nbytes); 114 bufflen -= nbytes; 115 total += nbytes; 116 117 } while (bufflen > 0); 118 119 return total; 120} 121 122ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen) 123{ 124 return usbip_net_xmit(sockfd, buff, bufflen, 0); 125} 126 127ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen) 128{ 129 return usbip_net_xmit(sockfd, buff, bufflen, 1); 130} 131 132static inline void usbip_net_pack_op_common(int pack, 133 struct op_common *op_common) 134{ 135 op_common->version = usbip_net_pack_uint16_t(pack, op_common->version); 136 op_common->code = usbip_net_pack_uint16_t(pack, op_common->code); 137 op_common->status = usbip_net_pack_uint32_t(pack, op_common->status); 138} 139 140int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status) 141{ 142 struct op_common op_common; 143 int rc; 144 145 memset(&op_common, 0, sizeof(op_common)); 146 147 op_common.version = USBIP_VERSION; 148 op_common.code = code; 149 op_common.status = status; 150 151 usbip_net_pack_op_common(1, &op_common); 152 153 rc = usbip_net_send(sockfd, &op_common, sizeof(op_common)); 154 if (rc < 0) { 155 dbg("usbip_net_send failed: %d", rc); 156 return -1; 157 } 158 159 return 0; 160} 161 162int usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status) 163{ 164 struct op_common op_common; 165 int rc; 166 167 memset(&op_common, 0, sizeof(op_common)); 168 169 rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common)); 170 if (rc < 0) { 171 dbg("usbip_net_recv failed: %d", rc); 172 goto err; 173 } 174 175 usbip_net_pack_op_common(0, &op_common); 176 177 if (op_common.version != USBIP_VERSION) { 178 err("USBIP Kernel and tool version mismatch: %d %d:", 179 op_common.version, USBIP_VERSION); 180 goto err; 181 } 182 183 switch (*code) { 184 case OP_UNSPEC: 185 break; 186 default: 187 if (op_common.code != *code) { 188 dbg("unexpected pdu %#0x for %#0x", op_common.code, 189 *code); 190 /* return error status */ 191 *status = ST_ERROR; 192 goto err; 193 } 194 } 195 196 *status = op_common.status; 197 198 if (op_common.status != ST_OK) { 199 dbg("request failed at peer: %d", op_common.status); 200 goto err; 201 } 202 203 *code = op_common.code; 204 205 return 0; 206err: 207 return -1; 208} 209 210int usbip_net_set_reuseaddr(int sockfd) 211{ 212 const int val = 1; 213 int ret; 214 215 ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 216 if (ret < 0) 217 dbg("setsockopt: SO_REUSEADDR"); 218 219 return ret; 220} 221 222int usbip_net_set_nodelay(int sockfd) 223{ 224 const int val = 1; 225 int ret; 226 227 ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); 228 if (ret < 0) 229 dbg("setsockopt: TCP_NODELAY"); 230 231 return ret; 232} 233 234int usbip_net_set_keepalive(int sockfd) 235{ 236 const int val = 1; 237 int ret; 238 239 ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); 240 if (ret < 0) 241 dbg("setsockopt: SO_KEEPALIVE"); 242 243 return ret; 244} 245 246int usbip_net_set_v6only(int sockfd) 247{ 248 const int val = 1; 249 int ret; 250 251 ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 252 if (ret < 0) 253 dbg("setsockopt: IPV6_V6ONLY"); 254 255 return ret; 256} 257 258/* 259 * IPv6 Ready 260 */ 261int usbip_net_tcp_connect(char *hostname, char *service) 262{ 263 struct addrinfo hints, *res, *rp; 264 int sockfd; 265 int ret; 266 267 memset(&hints, 0, sizeof(hints)); 268 hints.ai_family = AF_UNSPEC; 269 hints.ai_socktype = SOCK_STREAM; 270 271 /* get all possible addresses */ 272 ret = getaddrinfo(hostname, service, &hints, &res); 273 if (ret < 0) { 274 dbg("getaddrinfo: %s service %s: %s", hostname, service, 275 gai_strerror(ret)); 276 return ret; 277 } 278 279 /* try the addresses */ 280 for (rp = res; rp; rp = rp->ai_next) { 281 sockfd = socket(rp->ai_family, rp->ai_socktype, 282 rp->ai_protocol); 283 if (sockfd < 0) 284 continue; 285 286 /* should set TCP_NODELAY for usbip */ 287 usbip_net_set_nodelay(sockfd); 288 /* TODO: write code for heartbeat */ 289 usbip_net_set_keepalive(sockfd); 290 291 if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) 292 break; 293 294 close(sockfd); 295 } 296 297 freeaddrinfo(res); 298 299 if (!rp) 300 return EAI_SYSTEM; 301 302 return sockfd; 303}