18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 48c2ecf20Sopenharmony_ci * 2005-2007 Takahiro Hirofuchi 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <sys/socket.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <string.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <arpa/inet.h> 128c2ecf20Sopenharmony_ci#include <netdb.h> 138c2ecf20Sopenharmony_ci#include <netinet/tcp.h> 148c2ecf20Sopenharmony_ci#include <unistd.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#ifdef HAVE_LIBWRAP 178c2ecf20Sopenharmony_ci#include <tcpd.h> 188c2ecf20Sopenharmony_ci#endif 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "usbip_common.h" 218c2ecf20Sopenharmony_ci#include "usbip_network.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciint usbip_port = 3240; 248c2ecf20Sopenharmony_cichar *usbip_port_string = "3240"; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_civoid usbip_setup_port_number(char *arg) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci dbg("parsing port arg '%s'", arg); 298c2ecf20Sopenharmony_ci char *end; 308c2ecf20Sopenharmony_ci unsigned long int port = strtoul(arg, &end, 10); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (end == arg) { 338c2ecf20Sopenharmony_ci err("port: could not parse '%s' as a decimal integer", arg); 348c2ecf20Sopenharmony_ci return; 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci if (*end != '\0') { 388c2ecf20Sopenharmony_ci err("port: garbage at end of '%s'", arg); 398c2ecf20Sopenharmony_ci return; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (port > UINT16_MAX) { 438c2ecf20Sopenharmony_ci err("port: %s too high (max=%d)", 448c2ecf20Sopenharmony_ci arg, UINT16_MAX); 458c2ecf20Sopenharmony_ci return; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci usbip_port = port; 498c2ecf20Sopenharmony_ci usbip_port_string = arg; 508c2ecf20Sopenharmony_ci info("using port %d (\"%s\")", usbip_port, usbip_port_string); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciuint32_t usbip_net_pack_uint32_t(int pack, uint32_t num) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci uint32_t i; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (pack) 588c2ecf20Sopenharmony_ci i = htonl(num); 598c2ecf20Sopenharmony_ci else 608c2ecf20Sopenharmony_ci i = ntohl(num); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return i; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ciuint16_t usbip_net_pack_uint16_t(int pack, uint16_t num) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci uint16_t i; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (pack) 708c2ecf20Sopenharmony_ci i = htons(num); 718c2ecf20Sopenharmony_ci else 728c2ecf20Sopenharmony_ci i = ntohs(num); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return i; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_civoid usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci udev->busnum = usbip_net_pack_uint32_t(pack, udev->busnum); 808c2ecf20Sopenharmony_ci udev->devnum = usbip_net_pack_uint32_t(pack, udev->devnum); 818c2ecf20Sopenharmony_ci udev->speed = usbip_net_pack_uint32_t(pack, udev->speed); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci udev->idVendor = usbip_net_pack_uint16_t(pack, udev->idVendor); 848c2ecf20Sopenharmony_ci udev->idProduct = usbip_net_pack_uint16_t(pack, udev->idProduct); 858c2ecf20Sopenharmony_ci udev->bcdDevice = usbip_net_pack_uint16_t(pack, udev->bcdDevice); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_civoid usbip_net_pack_usb_interface(int pack __attribute__((unused)), 898c2ecf20Sopenharmony_ci struct usbip_usb_interface *udev 908c2ecf20Sopenharmony_ci __attribute__((unused))) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci /* uint8_t members need nothing */ 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen, 968c2ecf20Sopenharmony_ci int sending) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci ssize_t nbytes; 998c2ecf20Sopenharmony_ci ssize_t total = 0; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (!bufflen) 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci do { 1058c2ecf20Sopenharmony_ci if (sending) 1068c2ecf20Sopenharmony_ci nbytes = send(sockfd, buff, bufflen, 0); 1078c2ecf20Sopenharmony_ci else 1088c2ecf20Sopenharmony_ci nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (nbytes <= 0) 1118c2ecf20Sopenharmony_ci return -1; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci buff = (void *)((intptr_t) buff + nbytes); 1148c2ecf20Sopenharmony_ci bufflen -= nbytes; 1158c2ecf20Sopenharmony_ci total += nbytes; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci } while (bufflen > 0); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return total; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cissize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci return usbip_net_xmit(sockfd, buff, bufflen, 0); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cissize_t usbip_net_send(int sockfd, void *buff, size_t bufflen) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci return usbip_net_xmit(sockfd, buff, bufflen, 1); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic inline void usbip_net_pack_op_common(int pack, 1338c2ecf20Sopenharmony_ci struct op_common *op_common) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci op_common->version = usbip_net_pack_uint16_t(pack, op_common->version); 1368c2ecf20Sopenharmony_ci op_common->code = usbip_net_pack_uint16_t(pack, op_common->code); 1378c2ecf20Sopenharmony_ci op_common->status = usbip_net_pack_uint32_t(pack, op_common->status); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ciint usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct op_common op_common; 1438c2ecf20Sopenharmony_ci int rc; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci memset(&op_common, 0, sizeof(op_common)); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci op_common.version = USBIP_VERSION; 1488c2ecf20Sopenharmony_ci op_common.code = code; 1498c2ecf20Sopenharmony_ci op_common.status = status; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci usbip_net_pack_op_common(1, &op_common); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci rc = usbip_net_send(sockfd, &op_common, sizeof(op_common)); 1548c2ecf20Sopenharmony_ci if (rc < 0) { 1558c2ecf20Sopenharmony_ci dbg("usbip_net_send failed: %d", rc); 1568c2ecf20Sopenharmony_ci return -1; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciint usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct op_common op_common; 1658c2ecf20Sopenharmony_ci int rc; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci memset(&op_common, 0, sizeof(op_common)); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common)); 1708c2ecf20Sopenharmony_ci if (rc < 0) { 1718c2ecf20Sopenharmony_ci dbg("usbip_net_recv failed: %d", rc); 1728c2ecf20Sopenharmony_ci goto err; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci usbip_net_pack_op_common(0, &op_common); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (op_common.version != USBIP_VERSION) { 1788c2ecf20Sopenharmony_ci err("USBIP Kernel and tool version mismatch: %d %d:", 1798c2ecf20Sopenharmony_ci op_common.version, USBIP_VERSION); 1808c2ecf20Sopenharmony_ci goto err; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci switch (*code) { 1848c2ecf20Sopenharmony_ci case OP_UNSPEC: 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci default: 1878c2ecf20Sopenharmony_ci if (op_common.code != *code) { 1888c2ecf20Sopenharmony_ci dbg("unexpected pdu %#0x for %#0x", op_common.code, 1898c2ecf20Sopenharmony_ci *code); 1908c2ecf20Sopenharmony_ci /* return error status */ 1918c2ecf20Sopenharmony_ci *status = ST_ERROR; 1928c2ecf20Sopenharmony_ci goto err; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci *status = op_common.status; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (op_common.status != ST_OK) { 1998c2ecf20Sopenharmony_ci dbg("request failed at peer: %d", op_common.status); 2008c2ecf20Sopenharmony_ci goto err; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci *code = op_common.code; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_cierr: 2078c2ecf20Sopenharmony_ci return -1; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ciint usbip_net_set_reuseaddr(int sockfd) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci const int val = 1; 2138c2ecf20Sopenharmony_ci int ret; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 2168c2ecf20Sopenharmony_ci if (ret < 0) 2178c2ecf20Sopenharmony_ci dbg("setsockopt: SO_REUSEADDR"); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return ret; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ciint usbip_net_set_nodelay(int sockfd) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci const int val = 1; 2258c2ecf20Sopenharmony_ci int ret; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); 2288c2ecf20Sopenharmony_ci if (ret < 0) 2298c2ecf20Sopenharmony_ci dbg("setsockopt: TCP_NODELAY"); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return ret; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ciint usbip_net_set_keepalive(int sockfd) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci const int val = 1; 2378c2ecf20Sopenharmony_ci int ret; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); 2408c2ecf20Sopenharmony_ci if (ret < 0) 2418c2ecf20Sopenharmony_ci dbg("setsockopt: SO_KEEPALIVE"); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return ret; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciint usbip_net_set_v6only(int sockfd) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci const int val = 1; 2498c2ecf20Sopenharmony_ci int ret; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 2528c2ecf20Sopenharmony_ci if (ret < 0) 2538c2ecf20Sopenharmony_ci dbg("setsockopt: IPV6_V6ONLY"); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return ret; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/* 2598c2ecf20Sopenharmony_ci * IPv6 Ready 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ciint usbip_net_tcp_connect(char *hostname, char *service) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct addrinfo hints, *res, *rp; 2648c2ecf20Sopenharmony_ci int sockfd; 2658c2ecf20Sopenharmony_ci int ret; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci memset(&hints, 0, sizeof(hints)); 2688c2ecf20Sopenharmony_ci hints.ai_family = AF_UNSPEC; 2698c2ecf20Sopenharmony_ci hints.ai_socktype = SOCK_STREAM; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* get all possible addresses */ 2728c2ecf20Sopenharmony_ci ret = getaddrinfo(hostname, service, &hints, &res); 2738c2ecf20Sopenharmony_ci if (ret < 0) { 2748c2ecf20Sopenharmony_ci dbg("getaddrinfo: %s service %s: %s", hostname, service, 2758c2ecf20Sopenharmony_ci gai_strerror(ret)); 2768c2ecf20Sopenharmony_ci return ret; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* try the addresses */ 2808c2ecf20Sopenharmony_ci for (rp = res; rp; rp = rp->ai_next) { 2818c2ecf20Sopenharmony_ci sockfd = socket(rp->ai_family, rp->ai_socktype, 2828c2ecf20Sopenharmony_ci rp->ai_protocol); 2838c2ecf20Sopenharmony_ci if (sockfd < 0) 2848c2ecf20Sopenharmony_ci continue; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* should set TCP_NODELAY for usbip */ 2878c2ecf20Sopenharmony_ci usbip_net_set_nodelay(sockfd); 2888c2ecf20Sopenharmony_ci /* TODO: write code for heartbeat */ 2898c2ecf20Sopenharmony_ci usbip_net_set_keepalive(sockfd); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci close(sockfd); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci freeaddrinfo(res); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (!rp) 3008c2ecf20Sopenharmony_ci return EAI_SYSTEM; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return sockfd; 3038c2ecf20Sopenharmony_ci} 304