blob: a3833ff1561eaf1841e9c79ec804657b33b669c2 [file] [log] [blame]
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -07001/*
matt mooneyfb5ca812011-06-19 22:44:49 -07002 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -07004 *
matt mooneyfb5ca812011-06-19 22:44:49 -07005 * 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/>.
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070017 */
18
matt mooney1e35d872011-05-26 06:17:13 -070019#include <sys/socket.h>
matt mooney1e35d872011-05-26 06:17:13 -070020
21#include <string.h>
22
matt mooney35dd0c22011-05-27 01:44:14 -070023#include <arpa/inet.h>
matt mooney1e35d872011-05-26 06:17:13 -070024#include <netdb.h>
25#include <netinet/tcp.h>
26#include <unistd.h>
27
28#include "usbip_common.h"
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070029#include "usbip_network.h"
30
31void 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 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
matt mooney35dd0c22011-05-27 01:44:14 -070055void pack_usb_device(int pack, struct usbip_usb_device *udev)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070056{
57 pack_uint32_t(pack, &udev->busnum);
58 pack_uint32_t(pack, &udev->devnum);
59 pack_uint32_t(pack, &udev->speed );
60
61 pack_uint16_t(pack, &udev->idVendor );
62 pack_uint16_t(pack, &udev->idProduct);
63 pack_uint16_t(pack, &udev->bcdDevice);
64}
65
matt mooney968c6592011-05-14 03:55:17 -070066void pack_usb_interface(int pack __attribute__((unused)),
matt mooney35dd0c22011-05-27 01:44:14 -070067 struct usbip_usb_interface *udev __attribute__((unused)))
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070068{
69 /* uint8_t members need nothing */
70}
71
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070072static ssize_t usbip_xmit(int sockfd, void *buff, size_t bufflen, int sending)
73{
matt mooneyfb5ca812011-06-19 22:44:49 -070074 ssize_t nbytes;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070075 ssize_t total = 0;
76
77 if (!bufflen)
78 return 0;
79
80 do {
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070081 if (sending)
82 nbytes = send(sockfd, buff, bufflen, 0);
83 else
84 nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
85
86 if (nbytes <= 0)
87 return -1;
88
matt mooneyfb5ca812011-06-19 22:44:49 -070089 buff = (void *)((intptr_t) buff + nbytes);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070090 bufflen -= nbytes;
91 total += nbytes;
92
93 } while (bufflen > 0);
94
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070095 return total;
96}
97
98ssize_t usbip_recv(int sockfd, void *buff, size_t bufflen)
99{
100 return usbip_xmit(sockfd, buff, bufflen, 0);
101}
102
103ssize_t usbip_send(int sockfd, void *buff, size_t bufflen)
104{
105 return usbip_xmit(sockfd, buff, bufflen, 1);
106}
107
108int usbip_send_op_common(int sockfd, uint32_t code, uint32_t status)
109{
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700110 struct op_common op_common;
matt mooneyfb5ca812011-06-19 22:44:49 -0700111 int rc;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700112
matt mooney950a4cd2011-05-27 01:44:10 -0700113 memset(&op_common, 0, sizeof(op_common));
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700114
matt mooney35dd0c22011-05-27 01:44:14 -0700115 op_common.version = USBIP_VERSION;
116 op_common.code = code;
117 op_common.status = status;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700118
119 PACK_OP_COMMON(1, &op_common);
120
matt mooneyfb5ca812011-06-19 22:44:49 -0700121 rc = usbip_send(sockfd, &op_common, sizeof(op_common));
122 if (rc < 0) {
123 dbg("usbip_send failed: %d", rc);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700124 return -1;
125 }
126
127 return 0;
128}
129
130int usbip_recv_op_common(int sockfd, uint16_t *code)
131{
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700132 struct op_common op_common;
matt mooneyfb5ca812011-06-19 22:44:49 -0700133 int rc;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700134
matt mooney950a4cd2011-05-27 01:44:10 -0700135 memset(&op_common, 0, sizeof(op_common));
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700136
matt mooneyfb5ca812011-06-19 22:44:49 -0700137 rc = usbip_recv(sockfd, &op_common, sizeof(op_common));
138 if (rc < 0) {
139 dbg("usbip_recv failed: %d", rc);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700140 goto err;
141 }
142
143 PACK_OP_COMMON(0, &op_common);
144
145 if (op_common.version != USBIP_VERSION) {
matt mooneyfb5ca812011-06-19 22:44:49 -0700146 dbg("version mismatch: %d %d", op_common.version,
147 USBIP_VERSION);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700148 goto err;
149 }
150
matt mooneyfb5ca812011-06-19 22:44:49 -0700151 switch (*code) {
152 case OP_UNSPEC:
153 break;
154 default:
155 if (op_common.code != *code) {
156 dbg("unexpected pdu %#0x for %#0x", op_common.code,
157 *code);
158 goto err;
159 }
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700160 }
161
162 if (op_common.status != ST_OK) {
matt mooneyfb5ca812011-06-19 22:44:49 -0700163 dbg("request failed at peer: %d", op_common.status);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700164 goto err;
165 }
166
167 *code = op_common.code;
168
169 return 0;
170err:
171 return -1;
172}
173
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700174int usbip_set_reuseaddr(int sockfd)
175{
176 const int val = 1;
177 int ret;
178
179 ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
180 if (ret < 0)
matt mooneyfb5ca812011-06-19 22:44:49 -0700181 dbg("setsockopt: SO_REUSEADDR");
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700182
183 return ret;
184}
185
186int usbip_set_nodelay(int sockfd)
187{
188 const int val = 1;
189 int ret;
190
191 ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
192 if (ret < 0)
matt mooneyfb5ca812011-06-19 22:44:49 -0700193 dbg("setsockopt: TCP_NODELAY");
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700194
195 return ret;
196}
197
198int usbip_set_keepalive(int sockfd)
199{
200 const int val = 1;
201 int ret;
202
203 ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
204 if (ret < 0)
matt mooneyfb5ca812011-06-19 22:44:49 -0700205 dbg("setsockopt: SO_KEEPALIVE");
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700206
207 return ret;
208}
209
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700210/*
matt mooney1e35d872011-05-26 06:17:13 -0700211 * IPv6 Ready
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700212 */
matt mooneyfb5ca812011-06-19 22:44:49 -0700213int usbip_net_tcp_connect(char *hostname, char *service)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700214{
matt mooney1e35d872011-05-26 06:17:13 -0700215 struct addrinfo hints, *res, *rp;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700216 int sockfd;
matt mooney1e35d872011-05-26 06:17:13 -0700217 int ret;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700218
219 memset(&hints, 0, sizeof(hints));
matt mooney1e35d872011-05-26 06:17:13 -0700220 hints.ai_family = AF_UNSPEC;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700221 hints.ai_socktype = SOCK_STREAM;
222
223 /* get all possible addresses */
matt mooneyfb5ca812011-06-19 22:44:49 -0700224 ret = getaddrinfo(hostname, service, &hints, &res);
matt mooney1e35d872011-05-26 06:17:13 -0700225 if (ret < 0) {
matt mooneyfb5ca812011-06-19 22:44:49 -0700226 dbg("getaddrinfo: %s service %s: %s", hostname, service,
matt mooney1e35d872011-05-26 06:17:13 -0700227 gai_strerror(ret));
228 return ret;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700229 }
230
matt mooney1e35d872011-05-26 06:17:13 -0700231 /* try the addresses */
232 for (rp = res; rp; rp = rp->ai_next) {
233 sockfd = socket(rp->ai_family, rp->ai_socktype,
234 rp->ai_protocol);
235 if (sockfd < 0)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700236 continue;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700237
238 /* should set TCP_NODELAY for usbip */
239 usbip_set_nodelay(sockfd);
matt mooney1e35d872011-05-26 06:17:13 -0700240 /* TODO: write code for heartbeat */
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700241 usbip_set_keepalive(sockfd);
242
matt mooney1e35d872011-05-26 06:17:13 -0700243 if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
244 break;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700245
matt mooney1e35d872011-05-26 06:17:13 -0700246 close(sockfd);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700247 }
248
matt mooney1e35d872011-05-26 06:17:13 -0700249 if (!rp)
250 return EAI_SYSTEM;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700251
matt mooney1e35d872011-05-26 06:17:13 -0700252 freeaddrinfo(res);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700253
matt mooney1e35d872011-05-26 06:17:13 -0700254 return sockfd;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700255}