]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/usbip/userspace/src/usbip_network.c
Merge remote-tracking branch 'usb-gadget/next'
[karo-tx-linux.git] / drivers / staging / usbip / userspace / src / usbip_network.c
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
31 int usbip_port = 3240;
32 char *usbip_port_string = "3240";
33
34 void usbip_setup_port_number(char *arg)
35 {
36         dbg("parsing port arg '%s'", arg);
37         char *end;
38         unsigned long int port = strtoul(arg, &end, 10);
39
40         if (end == arg) {
41                 err("port: could not parse '%s' as a decimal integer", arg);
42                 return;
43         }
44
45         if (*end != '\0') {
46                 err("port: garbage at end of '%s'", arg);
47                 return;
48         }
49
50         if (port > UINT16_MAX) {
51                 err("port: %s too high (max=%d)",
52                     arg, UINT16_MAX);
53                 return;
54         }
55
56         usbip_port = port;
57         usbip_port_string = arg;
58         info("using port %d (\"%s\")", usbip_port, usbip_port_string);
59 }
60
61 void usbip_net_pack_uint32_t(int pack, uint32_t *num)
62 {
63         uint32_t i;
64
65         if (pack)
66                 i = htonl(*num);
67         else
68                 i = ntohl(*num);
69
70         *num = i;
71 }
72
73 void usbip_net_pack_uint16_t(int pack, uint16_t *num)
74 {
75         uint16_t i;
76
77         if (pack)
78                 i = htons(*num);
79         else
80                 i = ntohs(*num);
81
82         *num = i;
83 }
84
85 void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
86 {
87         usbip_net_pack_uint32_t(pack, &udev->busnum);
88         usbip_net_pack_uint32_t(pack, &udev->devnum);
89         usbip_net_pack_uint32_t(pack, &udev->speed);
90
91         usbip_net_pack_uint16_t(pack, &udev->idVendor);
92         usbip_net_pack_uint16_t(pack, &udev->idProduct);
93         usbip_net_pack_uint16_t(pack, &udev->bcdDevice);
94 }
95
96 void usbip_net_pack_usb_interface(int pack __attribute__((unused)),
97                                   struct usbip_usb_interface *udev
98                                   __attribute__((unused)))
99 {
100         /* uint8_t members need nothing */
101 }
102
103 static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
104                               int sending)
105 {
106         ssize_t nbytes;
107         ssize_t total = 0;
108
109         if (!bufflen)
110                 return 0;
111
112         do {
113                 if (sending)
114                         nbytes = send(sockfd, buff, bufflen, 0);
115                 else
116                         nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
117
118                 if (nbytes <= 0)
119                         return -1;
120
121                 buff     = (void *)((intptr_t) buff + nbytes);
122                 bufflen -= nbytes;
123                 total   += nbytes;
124
125         } while (bufflen > 0);
126
127         return total;
128 }
129
130 ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
131 {
132         return usbip_net_xmit(sockfd, buff, bufflen, 0);
133 }
134
135 ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
136 {
137         return usbip_net_xmit(sockfd, buff, bufflen, 1);
138 }
139
140 int 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         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
162 int usbip_net_recv_op_common(int sockfd, uint16_t *code)
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         PACK_OP_COMMON(0, &op_common);
176
177         if (op_common.version != USBIP_VERSION) {
178                 dbg("version mismatch: %d %d", op_common.version,
179                     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                         goto err;
191                 }
192         }
193
194         if (op_common.status != ST_OK) {
195                 dbg("request failed at peer: %d", op_common.status);
196                 goto err;
197         }
198
199         *code = op_common.code;
200
201         return 0;
202 err:
203         return -1;
204 }
205
206 int usbip_net_set_reuseaddr(int sockfd)
207 {
208         const int val = 1;
209         int ret;
210
211         ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
212         if (ret < 0)
213                 dbg("setsockopt: SO_REUSEADDR");
214
215         return ret;
216 }
217
218 int usbip_net_set_nodelay(int sockfd)
219 {
220         const int val = 1;
221         int ret;
222
223         ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
224         if (ret < 0)
225                 dbg("setsockopt: TCP_NODELAY");
226
227         return ret;
228 }
229
230 int usbip_net_set_keepalive(int sockfd)
231 {
232         const int val = 1;
233         int ret;
234
235         ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
236         if (ret < 0)
237                 dbg("setsockopt: SO_KEEPALIVE");
238
239         return ret;
240 }
241
242 /*
243  * IPv6 Ready
244  */
245 int usbip_net_tcp_connect(char *hostname, char *service)
246 {
247         struct addrinfo hints, *res, *rp;
248         int sockfd;
249         int ret;
250
251         memset(&hints, 0, sizeof(hints));
252         hints.ai_family = AF_UNSPEC;
253         hints.ai_socktype = SOCK_STREAM;
254
255         /* get all possible addresses */
256         ret = getaddrinfo(hostname, service, &hints, &res);
257         if (ret < 0) {
258                 dbg("getaddrinfo: %s service %s: %s", hostname, service,
259                     gai_strerror(ret));
260                 return ret;
261         }
262
263         /* try the addresses */
264         for (rp = res; rp; rp = rp->ai_next) {
265                 sockfd = socket(rp->ai_family, rp->ai_socktype,
266                                 rp->ai_protocol);
267                 if (sockfd < 0)
268                         continue;
269
270                 /* should set TCP_NODELAY for usbip */
271                 usbip_net_set_nodelay(sockfd);
272                 /* TODO: write code for heartbeat */
273                 usbip_net_set_keepalive(sockfd);
274
275                 if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
276                         break;
277
278                 close(sockfd);
279         }
280
281         freeaddrinfo(res);
282
283         if (!rp)
284                 return EAI_SYSTEM;
285
286         return sockfd;
287 }