/drivers/staging/usbip/userspace/src/usbip_network.c
C | 251 lines | 176 code | 61 blank | 14 comment | 22 complexity | 74e3a70f3f3e3fb2d20db8369b42429d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
1/*
2 *
3 * Copyright (C) 2005-2007 Takahiro Hirofuchi
4 */
5
6#include "usbip_network.h"
7
8void pack_uint32_t(int pack, uint32_t *num)
9{
10 uint32_t i;
11
12 if (pack)
13 i = htonl(*num);
14 else
15 i = ntohl(*num);
16
17 *num = i;
18}
19
20void pack_uint16_t(int pack, uint16_t *num)
21{
22 uint16_t i;
23
24 if (pack)
25 i = htons(*num);
26 else
27 i = ntohs(*num);
28
29 *num = i;
30}
31
32void pack_usb_device(int pack, struct usb_device *udev)
33{
34 pack_uint32_t(pack, &udev->busnum);
35 pack_uint32_t(pack, &udev->devnum);
36 pack_uint32_t(pack, &udev->speed );
37
38 pack_uint16_t(pack, &udev->idVendor );
39 pack_uint16_t(pack, &udev->idProduct);
40 pack_uint16_t(pack, &udev->bcdDevice);
41}
42
43void pack_usb_interface(int pack __attribute__((unused)),
44 struct usb_interface *udev __attribute__((unused)))
45{
46 /* uint8_t members need nothing */
47}
48
49
50static ssize_t usbip_xmit(int sockfd, void *buff, size_t bufflen, int sending)
51{
52 ssize_t total = 0;
53
54 if (!bufflen)
55 return 0;
56
57 do {
58 ssize_t nbytes;
59
60 if (sending)
61 nbytes = send(sockfd, buff, bufflen, 0);
62 else
63 nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
64
65 if (nbytes <= 0)
66 return -1;
67
68 buff = (void *) ((intptr_t) buff + nbytes);
69 bufflen -= nbytes;
70 total += nbytes;
71
72 } while (bufflen > 0);
73
74
75 return total;
76}
77
78ssize_t usbip_recv(int sockfd, void *buff, size_t bufflen)
79{
80 return usbip_xmit(sockfd, buff, bufflen, 0);
81}
82
83ssize_t usbip_send(int sockfd, void *buff, size_t bufflen)
84{
85 return usbip_xmit(sockfd, buff, bufflen, 1);
86}
87
88int usbip_send_op_common(int sockfd, uint32_t code, uint32_t status)
89{
90 int ret;
91 struct op_common op_common;
92
93 bzero(&op_common, sizeof(op_common));
94
95 op_common.version = USBIP_VERSION;
96 op_common.code = code;
97 op_common.status = status;
98
99 PACK_OP_COMMON(1, &op_common);
100
101 ret = usbip_send(sockfd, (void *) &op_common, sizeof(op_common));
102 if (ret < 0) {
103 err("send op_common");
104 return -1;
105 }
106
107 return 0;
108}
109
110int usbip_recv_op_common(int sockfd, uint16_t *code)
111{
112 int ret;
113 struct op_common op_common;
114
115 bzero(&op_common, sizeof(op_common));
116
117 ret = usbip_recv(sockfd, (void *) &op_common, sizeof(op_common));
118 if (ret < 0) {
119 err("recv op_common, %d", ret);
120 goto err;
121 }
122
123 PACK_OP_COMMON(0, &op_common);
124
125 if (op_common.version != USBIP_VERSION) {
126 err("version mismatch, %d %d", op_common.version, USBIP_VERSION);
127 goto err;
128 }
129
130 switch(*code) {
131 case OP_UNSPEC:
132 break;
133 default:
134 if (op_common.code != *code) {
135 info("unexpected pdu %d for %d", op_common.code, *code);
136 goto err;
137 }
138 }
139
140 if (op_common.status != ST_OK) {
141 info("request failed at peer, %d", op_common.status);
142 goto err;
143 }
144
145 *code = op_common.code;
146
147 return 0;
148err:
149 return -1;
150}
151
152
153int usbip_set_reuseaddr(int sockfd)
154{
155 const int val = 1;
156 int ret;
157
158 ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
159 if (ret < 0)
160 err("setsockopt SO_REUSEADDR");
161
162 return ret;
163}
164
165int usbip_set_nodelay(int sockfd)
166{
167 const int val = 1;
168 int ret;
169
170 ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
171 if (ret < 0)
172 err("setsockopt TCP_NODELAY");
173
174 return ret;
175}
176
177int usbip_set_keepalive(int sockfd)
178{
179 const int val = 1;
180 int ret;
181
182 ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
183 if (ret < 0)
184 err("setsockopt SO_KEEPALIVE");
185
186 return ret;
187}
188
189/* IPv6 Ready */
190/*
191 * moved here from vhci_attach.c
192 */
193int tcp_connect(char *hostname, char *service)
194{
195 struct addrinfo hints, *res, *res0;
196 int sockfd;
197 int err;
198
199
200 memset(&hints, 0, sizeof(hints));
201 hints.ai_socktype = SOCK_STREAM;
202
203 /* get all possible addresses */
204 err = getaddrinfo(hostname, service, &hints, &res0);
205 if (err) {
206 err("%s %s: %s", hostname, service, gai_strerror(err));
207 return -1;
208 }
209
210 /* try all the addresses */
211 for (res = res0; res; res = res->ai_next) {
212 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
213
214 err = getnameinfo(res->ai_addr, res->ai_addrlen,
215 hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
216 if (err) {
217 err("%s %s: %s", hostname, service, gai_strerror(err));
218 continue;
219 }
220
221 dbg("trying %s port %s\n", hbuf, sbuf);
222
223 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
224 if (sockfd < 0) {
225 err("socket");
226 continue;
227 }
228
229 /* should set TCP_NODELAY for usbip */
230 usbip_set_nodelay(sockfd);
231 /* TODO: write code for heatbeat */
232 usbip_set_keepalive(sockfd);
233
234 err = connect(sockfd, res->ai_addr, res->ai_addrlen);
235 if (err < 0) {
236 close(sockfd);
237 continue;
238 }
239
240 /* connected */
241 dbg("connected to %s:%s", hbuf, sbuf);
242 freeaddrinfo(res0);
243 return sockfd;
244 }
245
246
247 dbg("%s:%s, %s", hostname, service, "no destination to connect to");
248 freeaddrinfo(res0);
249
250 return -1;
251}