Merge tag 'tty-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[platform/adaptation/renesas_rcar/renesas_kernel.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 void 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
43 void 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
55 void 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
66 void 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
73 static 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
100 ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
101 {
102         return usbip_net_xmit(sockfd, buff, bufflen, 0);
103 }
104
105 ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
106 {
107         return usbip_net_xmit(sockfd, buff, bufflen, 1);
108 }
109
110 int 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
132 int 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;
172 err:
173         return -1;
174 }
175
176 int 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
188 int 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
200 int 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  */
215 int 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 }