162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 462306a36Sopenharmony_ci * 2005-2007 Takahiro Hirofuchi 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <sys/socket.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <string.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <arpa/inet.h> 1262306a36Sopenharmony_ci#include <netdb.h> 1362306a36Sopenharmony_ci#include <netinet/tcp.h> 1462306a36Sopenharmony_ci#include <unistd.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#ifdef HAVE_LIBWRAP 1762306a36Sopenharmony_ci#include <tcpd.h> 1862306a36Sopenharmony_ci#endif 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "usbip_common.h" 2162306a36Sopenharmony_ci#include "usbip_network.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciint usbip_port = 3240; 2462306a36Sopenharmony_cichar *usbip_port_string = "3240"; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_civoid usbip_setup_port_number(char *arg) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci dbg("parsing port arg '%s'", arg); 2962306a36Sopenharmony_ci char *end; 3062306a36Sopenharmony_ci unsigned long int port = strtoul(arg, &end, 10); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (end == arg) { 3362306a36Sopenharmony_ci err("port: could not parse '%s' as a decimal integer", arg); 3462306a36Sopenharmony_ci return; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (*end != '\0') { 3862306a36Sopenharmony_ci err("port: garbage at end of '%s'", arg); 3962306a36Sopenharmony_ci return; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (port > UINT16_MAX) { 4362306a36Sopenharmony_ci err("port: %s too high (max=%d)", 4462306a36Sopenharmony_ci arg, UINT16_MAX); 4562306a36Sopenharmony_ci return; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci usbip_port = port; 4962306a36Sopenharmony_ci usbip_port_string = arg; 5062306a36Sopenharmony_ci info("using port %d (\"%s\")", usbip_port, usbip_port_string); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciuint32_t usbip_net_pack_uint32_t(int pack, uint32_t num) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci uint32_t i; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (pack) 5862306a36Sopenharmony_ci i = htonl(num); 5962306a36Sopenharmony_ci else 6062306a36Sopenharmony_ci i = ntohl(num); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return i; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciuint16_t usbip_net_pack_uint16_t(int pack, uint16_t num) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci uint16_t i; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (pack) 7062306a36Sopenharmony_ci i = htons(num); 7162306a36Sopenharmony_ci else 7262306a36Sopenharmony_ci i = ntohs(num); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return i; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_civoid usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci udev->busnum = usbip_net_pack_uint32_t(pack, udev->busnum); 8062306a36Sopenharmony_ci udev->devnum = usbip_net_pack_uint32_t(pack, udev->devnum); 8162306a36Sopenharmony_ci udev->speed = usbip_net_pack_uint32_t(pack, udev->speed); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci udev->idVendor = usbip_net_pack_uint16_t(pack, udev->idVendor); 8462306a36Sopenharmony_ci udev->idProduct = usbip_net_pack_uint16_t(pack, udev->idProduct); 8562306a36Sopenharmony_ci udev->bcdDevice = usbip_net_pack_uint16_t(pack, udev->bcdDevice); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_civoid usbip_net_pack_usb_interface(int pack __attribute__((unused)), 8962306a36Sopenharmony_ci struct usbip_usb_interface *udev 9062306a36Sopenharmony_ci __attribute__((unused))) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci /* uint8_t members need nothing */ 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen, 9662306a36Sopenharmony_ci int sending) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci ssize_t nbytes; 9962306a36Sopenharmony_ci ssize_t total = 0; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (!bufflen) 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci do { 10562306a36Sopenharmony_ci if (sending) 10662306a36Sopenharmony_ci nbytes = send(sockfd, buff, bufflen, 0); 10762306a36Sopenharmony_ci else 10862306a36Sopenharmony_ci nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (nbytes <= 0) 11162306a36Sopenharmony_ci return -1; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci buff = (void *)((intptr_t) buff + nbytes); 11462306a36Sopenharmony_ci bufflen -= nbytes; 11562306a36Sopenharmony_ci total += nbytes; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci } while (bufflen > 0); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return total; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cissize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return usbip_net_xmit(sockfd, buff, bufflen, 0); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cissize_t usbip_net_send(int sockfd, void *buff, size_t bufflen) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci return usbip_net_xmit(sockfd, buff, bufflen, 1); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline void usbip_net_pack_op_common(int pack, 13362306a36Sopenharmony_ci struct op_common *op_common) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci op_common->version = usbip_net_pack_uint16_t(pack, op_common->version); 13662306a36Sopenharmony_ci op_common->code = usbip_net_pack_uint16_t(pack, op_common->code); 13762306a36Sopenharmony_ci op_common->status = usbip_net_pack_uint32_t(pack, op_common->status); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciint usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct op_common op_common; 14362306a36Sopenharmony_ci int rc; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci memset(&op_common, 0, sizeof(op_common)); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci op_common.version = USBIP_VERSION; 14862306a36Sopenharmony_ci op_common.code = code; 14962306a36Sopenharmony_ci op_common.status = status; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci usbip_net_pack_op_common(1, &op_common); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci rc = usbip_net_send(sockfd, &op_common, sizeof(op_common)); 15462306a36Sopenharmony_ci if (rc < 0) { 15562306a36Sopenharmony_ci dbg("usbip_net_send failed: %d", rc); 15662306a36Sopenharmony_ci return -1; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciint usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct op_common op_common; 16562306a36Sopenharmony_ci int rc; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci memset(&op_common, 0, sizeof(op_common)); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common)); 17062306a36Sopenharmony_ci if (rc < 0) { 17162306a36Sopenharmony_ci dbg("usbip_net_recv failed: %d", rc); 17262306a36Sopenharmony_ci goto err; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci usbip_net_pack_op_common(0, &op_common); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (op_common.version != USBIP_VERSION) { 17862306a36Sopenharmony_ci err("USBIP Kernel and tool version mismatch: %d %d:", 17962306a36Sopenharmony_ci op_common.version, USBIP_VERSION); 18062306a36Sopenharmony_ci goto err; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci switch (*code) { 18462306a36Sopenharmony_ci case OP_UNSPEC: 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci default: 18762306a36Sopenharmony_ci if (op_common.code != *code) { 18862306a36Sopenharmony_ci dbg("unexpected pdu %#0x for %#0x", op_common.code, 18962306a36Sopenharmony_ci *code); 19062306a36Sopenharmony_ci /* return error status */ 19162306a36Sopenharmony_ci *status = ST_ERROR; 19262306a36Sopenharmony_ci goto err; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci *status = op_common.status; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (op_common.status != ST_OK) { 19962306a36Sopenharmony_ci dbg("request failed at peer: %d", op_common.status); 20062306a36Sopenharmony_ci goto err; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci *code = op_common.code; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_cierr: 20762306a36Sopenharmony_ci return -1; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ciint usbip_net_set_reuseaddr(int sockfd) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci const int val = 1; 21362306a36Sopenharmony_ci int ret; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 21662306a36Sopenharmony_ci if (ret < 0) 21762306a36Sopenharmony_ci dbg("setsockopt: SO_REUSEADDR"); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return ret; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ciint usbip_net_set_nodelay(int sockfd) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci const int val = 1; 22562306a36Sopenharmony_ci int ret; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); 22862306a36Sopenharmony_ci if (ret < 0) 22962306a36Sopenharmony_ci dbg("setsockopt: TCP_NODELAY"); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return ret; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciint usbip_net_set_keepalive(int sockfd) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci const int val = 1; 23762306a36Sopenharmony_ci int ret; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); 24062306a36Sopenharmony_ci if (ret < 0) 24162306a36Sopenharmony_ci dbg("setsockopt: SO_KEEPALIVE"); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return ret; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciint usbip_net_set_v6only(int sockfd) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci const int val = 1; 24962306a36Sopenharmony_ci int ret; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 25262306a36Sopenharmony_ci if (ret < 0) 25362306a36Sopenharmony_ci dbg("setsockopt: IPV6_V6ONLY"); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return ret; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* 25962306a36Sopenharmony_ci * IPv6 Ready 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ciint usbip_net_tcp_connect(char *hostname, char *service) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct addrinfo hints, *res, *rp; 26462306a36Sopenharmony_ci int sockfd; 26562306a36Sopenharmony_ci int ret; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci memset(&hints, 0, sizeof(hints)); 26862306a36Sopenharmony_ci hints.ai_family = AF_UNSPEC; 26962306a36Sopenharmony_ci hints.ai_socktype = SOCK_STREAM; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* get all possible addresses */ 27262306a36Sopenharmony_ci ret = getaddrinfo(hostname, service, &hints, &res); 27362306a36Sopenharmony_ci if (ret < 0) { 27462306a36Sopenharmony_ci dbg("getaddrinfo: %s service %s: %s", hostname, service, 27562306a36Sopenharmony_ci gai_strerror(ret)); 27662306a36Sopenharmony_ci return ret; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* try the addresses */ 28062306a36Sopenharmony_ci for (rp = res; rp; rp = rp->ai_next) { 28162306a36Sopenharmony_ci sockfd = socket(rp->ai_family, rp->ai_socktype, 28262306a36Sopenharmony_ci rp->ai_protocol); 28362306a36Sopenharmony_ci if (sockfd < 0) 28462306a36Sopenharmony_ci continue; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* should set TCP_NODELAY for usbip */ 28762306a36Sopenharmony_ci usbip_net_set_nodelay(sockfd); 28862306a36Sopenharmony_ci /* TODO: write code for heartbeat */ 28962306a36Sopenharmony_ci usbip_net_set_keepalive(sockfd); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci close(sockfd); 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci freeaddrinfo(res); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (!rp) 30062306a36Sopenharmony_ci return EAI_SYSTEM; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return sockfd; 30362306a36Sopenharmony_ci} 304