linux/drivers/staging/usbip/userspace/src/usbip_network.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
   3 *               2005-2007 Takahiro Hirofuchi
   4 *
   5 * This program is free software: you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation, either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17 */
  18
  19#include <sys/socket.h>
  20
  21#include <string.h>
  22
  23#include <arpa/inet.h>
  24#include <netdb.h>
  25#include <netinet/tcp.h>
  26#include <unistd.h>
  27
  28#include "usbip_common.h"
  29#include "usbip_network.h"
  30
  31void usbip_net_pack_uint32_t(int pack, uint32_t *num)
  32{
  33        uint32_t i;
  34
  35        if (pack)
  36                i = htonl(*num);
  37        else
  38                i = ntohl(*num);
  39
  40        *num = i;
  41}
  42
  43void usbip_net_pack_uint16_t(int pack, uint16_t *num)
  44{
  45        uint16_t i;
  46
  47        if (pack)
  48                i = htons(*num);
  49        else
  50                i = ntohs(*num);
  51
  52        *num = i;
  53}
  54
  55void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
  56{
  57        usbip_net_pack_uint32_t(pack, &udev->busnum);
  58        usbip_net_pack_uint32_t(pack, &udev->devnum);
  59        usbip_net_pack_uint32_t(pack, &udev->speed);
  60
  61        usbip_net_pack_uint16_t(pack, &udev->idVendor);
  62        usbip_net_pack_uint16_t(pack, &udev->idProduct);
  63        usbip_net_pack_uint16_t(pack, &udev->bcdDevice);
  64}
  65
  66void usbip_net_pack_usb_interface(int pack __attribute__((unused)),
  67                                  struct usbip_usb_interface *udev
  68                                  __attribute__((unused)))
  69{
  70        /* uint8_t members need nothing */
  71}
  72
  73static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
  74                              int sending)
  75{
  76        ssize_t nbytes;
  77        ssize_t total = 0;
  78
  79        if (!bufflen)
  80                return 0;
  81
  82        do {
  83                if (sending)
  84                        nbytes = send(sockfd, buff, bufflen, 0);
  85                else
  86                        nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
  87
  88                if (nbytes <= 0)
  89                        return -1;
  90
  91                buff     = (void *)((intptr_t) buff + nbytes);
  92                bufflen -= nbytes;
  93                total   += nbytes;
  94
  95        } while (bufflen > 0);
  96
  97        return total;
  98}
  99
 100ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
 101{
 102        return usbip_net_xmit(sockfd, buff, bufflen, 0);
 103}
 104
 105ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
 106{
 107        return usbip_net_xmit(sockfd, buff, bufflen, 1);
 108}
 109
 110int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
 111{
 112        struct op_common op_common;
 113        int rc;
 114
 115        memset(&op_common, 0, sizeof(op_common));
 116
 117        op_common.version = USBIP_VERSION;
 118        op_common.code    = code;
 119        op_common.status  = status;
 120
 121        PACK_OP_COMMON(1, &op_common);
 122
 123        rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));
 124        if (rc < 0) {
 125                dbg("usbip_net_send failed: %d", rc);
 126                return -1;
 127        }
 128
 129        return 0;
 130}
 131
 132int usbip_net_recv_op_common(int sockfd, uint16_t *code)
 133{
 134        struct op_common op_common;
 135        int rc;
 136
 137        memset(&op_common, 0, sizeof(op_common));
 138
 139        rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
 140        if (rc < 0) {
 141                dbg("usbip_net_recv failed: %d", rc);
 142                goto err;
 143        }
 144
 145        PACK_OP_COMMON(0, &op_common);
 146
 147        if (op_common.version != USBIP_VERSION) {
 148                dbg("version mismatch: %d %d", op_common.version,
 149                    USBIP_VERSION);
 150                goto err;
 151        }
 152
 153        switch (*code) {
 154        case OP_UNSPEC:
 155                break;
 156        default:
 157                if (op_common.code != *code) {
 158                        dbg("unexpected pdu %#0x for %#0x", op_common.code,
 159                            *code);
 160                        goto err;
 161                }
 162        }
 163
 164        if (op_common.status != ST_OK) {
 165                dbg("request failed at peer: %d", op_common.status);
 166                goto err;
 167        }
 168
 169        *code = op_common.code;
 170
 171        return 0;
 172err:
 173        return -1;
 174}
 175
 176int usbip_net_set_reuseaddr(int sockfd)
 177{
 178        const int val = 1;
 179        int ret;
 180
 181        ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
 182        if (ret < 0)
 183                dbg("setsockopt: SO_REUSEADDR");
 184
 185        return ret;
 186}
 187
 188int usbip_net_set_nodelay(int sockfd)
 189{
 190        const int val = 1;
 191        int ret;
 192
 193        ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
 194        if (ret < 0)
 195                dbg("setsockopt: TCP_NODELAY");
 196
 197        return ret;
 198}
 199
 200int usbip_net_set_keepalive(int sockfd)
 201{
 202        const int val = 1;
 203        int ret;
 204
 205        ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
 206        if (ret < 0)
 207                dbg("setsockopt: SO_KEEPALIVE");
 208
 209        return ret;
 210}
 211
 212/*
 213 * IPv6 Ready
 214 */
 215int usbip_net_tcp_connect(char *hostname, char *service)
 216{
 217        struct addrinfo hints, *res, *rp;
 218        int sockfd;
 219        int ret;
 220
 221        memset(&hints, 0, sizeof(hints));
 222        hints.ai_family = AF_UNSPEC;
 223        hints.ai_socktype = SOCK_STREAM;
 224
 225        /* get all possible addresses */
 226        ret = getaddrinfo(hostname, service, &hints, &res);
 227        if (ret < 0) {
 228                dbg("getaddrinfo: %s service %s: %s", hostname, service,
 229                    gai_strerror(ret));
 230                return ret;
 231        }
 232
 233        /* try the addresses */
 234        for (rp = res; rp; rp = rp->ai_next) {
 235                sockfd = socket(rp->ai_family, rp->ai_socktype,
 236                                rp->ai_protocol);
 237                if (sockfd < 0)
 238                        continue;
 239
 240                /* should set TCP_NODELAY for usbip */
 241                usbip_net_set_nodelay(sockfd);
 242                /* TODO: write code for heartbeat */
 243                usbip_net_set_keepalive(sockfd);
 244
 245                if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
 246                        break;
 247
 248                close(sockfd);
 249        }
 250
 251        freeaddrinfo(res);
 252
 253        if (!rp)
 254                return EAI_SYSTEM;
 255
 256        return sockfd;
 257}
 258