Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 only, | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
60ecf96e | 18 | * http://www.gnu.org/licenses/gpl-2.0.html |
d7e09d03 PT |
19 | * |
20 | * GPL HEADER END | |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. | |
24 | * Use is subject to license terms. | |
25 | * | |
1dc563a6 | 26 | * Copyright (c) 2012, 2015, Intel Corporation. |
d7e09d03 PT |
27 | */ |
28 | /* | |
29 | * This file is part of Lustre, http://www.lustre.org/ | |
60ecf96e | 30 | * Lustre is a trademark of Seagate, Inc. |
d7e09d03 PT |
31 | */ |
32 | #define DEBUG_SUBSYSTEM S_LNET | |
33 | ||
d7e09d03 PT |
34 | #include <linux/if.h> |
35 | #include <linux/in.h> | |
5c2414ef | 36 | #include <linux/net.h> |
d7e09d03 | 37 | #include <linux/file.h> |
5c2414ef | 38 | #include <linux/pagemap.h> |
d7e09d03 PT |
39 | /* For sys_open & sys_close */ |
40 | #include <linux/syscalls.h> | |
5c2414ef JS |
41 | #include <net/sock.h> |
42 | ||
43 | #include "../../include/linux/libcfs/libcfs.h" | |
44 | #include "../../include/linux/lnet/lib-lnet.h" | |
45 | ||
46 | static int | |
47 | kernel_sock_unlocked_ioctl(struct file *filp, int cmd, unsigned long arg) | |
48 | { | |
49 | mm_segment_t oldfs = get_fs(); | |
50 | int err; | |
51 | ||
52 | set_fs(KERNEL_DS); | |
53 | err = filp->f_op->unlocked_ioctl(filp, cmd, arg); | |
54 | set_fs(oldfs); | |
55 | ||
56 | return err; | |
57 | } | |
d7e09d03 | 58 | |
2a74b9bd | 59 | static int |
1ad6a73e | 60 | lnet_sock_ioctl(int cmd, unsigned long arg) |
d7e09d03 | 61 | { |
73092892 JS |
62 | struct file *sock_filp; |
63 | struct socket *sock; | |
64 | int rc; | |
d7e09d03 | 65 | |
73092892 | 66 | rc = sock_create(PF_INET, SOCK_STREAM, 0, &sock); |
d7e09d03 | 67 | if (rc != 0) { |
73092892 | 68 | CERROR("Can't create socket: %d\n", rc); |
d7e09d03 PT |
69 | return rc; |
70 | } | |
3eeb821e OD |
71 | |
72 | sock_filp = sock_alloc_file(sock, 0, NULL); | |
73 | if (IS_ERR(sock_filp)) { | |
74 | sock_release(sock); | |
75 | rc = PTR_ERR(sock_filp); | |
76 | goto out; | |
77 | } | |
78 | ||
5c2414ef | 79 | rc = kernel_sock_unlocked_ioctl(sock_filp, cmd, arg); |
3eeb821e OD |
80 | |
81 | fput(sock_filp); | |
82 | out: | |
d7e09d03 PT |
83 | return rc; |
84 | } | |
85 | ||
86 | int | |
73092892 | 87 | lnet_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask) |
d7e09d03 | 88 | { |
73092892 JS |
89 | struct ifreq ifr; |
90 | int nob; | |
91 | int rc; | |
92 | __u32 val; | |
d7e09d03 PT |
93 | |
94 | nob = strnlen(name, IFNAMSIZ); | |
95 | if (nob == IFNAMSIZ) { | |
96 | CERROR("Interface name %s too long\n", name); | |
97 | return -EINVAL; | |
98 | } | |
99 | ||
73092892 | 100 | CLASSERT(sizeof(ifr.ifr_name) >= IFNAMSIZ); |
d7e09d03 PT |
101 | |
102 | strcpy(ifr.ifr_name, name); | |
1ad6a73e | 103 | rc = lnet_sock_ioctl(SIOCGIFFLAGS, (unsigned long)&ifr); |
d7e09d03 PT |
104 | if (rc != 0) { |
105 | CERROR("Can't get flags for interface %s\n", name); | |
106 | return rc; | |
107 | } | |
108 | ||
109 | if ((ifr.ifr_flags & IFF_UP) == 0) { | |
110 | CDEBUG(D_NET, "Interface %s down\n", name); | |
111 | *up = 0; | |
112 | *ip = *mask = 0; | |
113 | return 0; | |
114 | } | |
d7e09d03 PT |
115 | *up = 1; |
116 | ||
117 | strcpy(ifr.ifr_name, name); | |
118 | ifr.ifr_addr.sa_family = AF_INET; | |
1ad6a73e | 119 | rc = lnet_sock_ioctl(SIOCGIFADDR, (unsigned long)&ifr); |
d7e09d03 PT |
120 | if (rc != 0) { |
121 | CERROR("Can't get IP address for interface %s\n", name); | |
122 | return rc; | |
123 | } | |
124 | ||
125 | val = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; | |
126 | *ip = ntohl(val); | |
127 | ||
128 | strcpy(ifr.ifr_name, name); | |
129 | ifr.ifr_addr.sa_family = AF_INET; | |
1ad6a73e | 130 | rc = lnet_sock_ioctl(SIOCGIFNETMASK, (unsigned long)&ifr); |
d7e09d03 PT |
131 | if (rc != 0) { |
132 | CERROR("Can't get netmask for interface %s\n", name); | |
133 | return rc; | |
134 | } | |
135 | ||
136 | val = ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr; | |
137 | *mask = ntohl(val); | |
138 | ||
139 | return 0; | |
140 | } | |
1ad6a73e | 141 | EXPORT_SYMBOL(lnet_ipif_query); |
d7e09d03 PT |
142 | |
143 | int | |
73092892 | 144 | lnet_ipif_enumerate(char ***namesp) |
d7e09d03 PT |
145 | { |
146 | /* Allocate and fill in 'names', returning # interfaces/error */ | |
73092892 JS |
147 | char **names; |
148 | int toobig; | |
149 | int nalloc; | |
150 | int nfound; | |
151 | struct ifreq *ifr; | |
152 | struct ifconf ifc; | |
153 | int rc; | |
154 | int nob; | |
155 | int i; | |
d7e09d03 PT |
156 | |
157 | nalloc = 16; /* first guess at max interfaces */ | |
158 | toobig = 0; | |
159 | for (;;) { | |
160 | if (nalloc * sizeof(*ifr) > PAGE_CACHE_SIZE) { | |
161 | toobig = 1; | |
162 | nalloc = PAGE_CACHE_SIZE/sizeof(*ifr); | |
163 | CWARN("Too many interfaces: only enumerating first %d\n", | |
164 | nalloc); | |
165 | } | |
166 | ||
167 | LIBCFS_ALLOC(ifr, nalloc * sizeof(*ifr)); | |
168 | if (ifr == NULL) { | |
73092892 JS |
169 | CERROR("ENOMEM enumerating up to %d interfaces\n", |
170 | nalloc); | |
d7e09d03 PT |
171 | rc = -ENOMEM; |
172 | goto out0; | |
173 | } | |
174 | ||
175 | ifc.ifc_buf = (char *)ifr; | |
176 | ifc.ifc_len = nalloc * sizeof(*ifr); | |
177 | ||
1ad6a73e | 178 | rc = lnet_sock_ioctl(SIOCGIFCONF, (unsigned long)&ifc); |
d7e09d03 | 179 | if (rc < 0) { |
73092892 | 180 | CERROR("Error %d enumerating interfaces\n", rc); |
d7e09d03 PT |
181 | goto out1; |
182 | } | |
183 | ||
73092892 | 184 | LASSERT(rc == 0); |
d7e09d03 PT |
185 | |
186 | nfound = ifc.ifc_len/sizeof(*ifr); | |
73092892 | 187 | LASSERT(nfound <= nalloc); |
d7e09d03 PT |
188 | |
189 | if (nfound < nalloc || toobig) | |
190 | break; | |
191 | ||
192 | LIBCFS_FREE(ifr, nalloc * sizeof(*ifr)); | |
193 | nalloc *= 2; | |
194 | } | |
195 | ||
196 | if (nfound == 0) | |
197 | goto out1; | |
198 | ||
199 | LIBCFS_ALLOC(names, nfound * sizeof(*names)); | |
200 | if (names == NULL) { | |
201 | rc = -ENOMEM; | |
202 | goto out1; | |
203 | } | |
d7e09d03 PT |
204 | |
205 | for (i = 0; i < nfound; i++) { | |
73092892 | 206 | nob = strnlen(ifr[i].ifr_name, IFNAMSIZ); |
d7e09d03 PT |
207 | if (nob == IFNAMSIZ) { |
208 | /* no space for terminating NULL */ | |
209 | CERROR("interface name %.*s too long (%d max)\n", | |
210 | nob, ifr[i].ifr_name, IFNAMSIZ); | |
211 | rc = -ENAMETOOLONG; | |
212 | goto out2; | |
213 | } | |
214 | ||
215 | LIBCFS_ALLOC(names[i], IFNAMSIZ); | |
216 | if (names[i] == NULL) { | |
217 | rc = -ENOMEM; | |
218 | goto out2; | |
219 | } | |
220 | ||
221 | memcpy(names[i], ifr[i].ifr_name, nob); | |
222 | names[i][nob] = 0; | |
223 | } | |
224 | ||
225 | *namesp = names; | |
226 | rc = nfound; | |
227 | ||
73092892 | 228 | out2: |
d7e09d03 | 229 | if (rc < 0) |
1ad6a73e | 230 | lnet_ipif_free_enumeration(names, nfound); |
73092892 | 231 | out1: |
d7e09d03 | 232 | LIBCFS_FREE(ifr, nalloc * sizeof(*ifr)); |
73092892 | 233 | out0: |
d7e09d03 PT |
234 | return rc; |
235 | } | |
1ad6a73e | 236 | EXPORT_SYMBOL(lnet_ipif_enumerate); |
d7e09d03 PT |
237 | |
238 | void | |
73092892 | 239 | lnet_ipif_free_enumeration(char **names, int n) |
d7e09d03 | 240 | { |
73092892 | 241 | int i; |
d7e09d03 | 242 | |
73092892 | 243 | LASSERT(n > 0); |
d7e09d03 PT |
244 | |
245 | for (i = 0; i < n && names[i] != NULL; i++) | |
246 | LIBCFS_FREE(names[i], IFNAMSIZ); | |
247 | ||
248 | LIBCFS_FREE(names, n * sizeof(*names)); | |
249 | } | |
1ad6a73e | 250 | EXPORT_SYMBOL(lnet_ipif_free_enumeration); |
d7e09d03 PT |
251 | |
252 | int | |
73092892 | 253 | lnet_sock_write(struct socket *sock, void *buffer, int nob, int timeout) |
d7e09d03 | 254 | { |
73092892 JS |
255 | int rc; |
256 | long ticks = timeout * HZ; | |
257 | unsigned long then; | |
d7e09d03 PT |
258 | struct timeval tv; |
259 | ||
73092892 | 260 | LASSERT(nob > 0); |
4420cfd3 JS |
261 | /* |
262 | * Caller may pass a zero timeout if she thinks the socket buffer is | |
263 | * empty enough to take the whole message immediately | |
264 | */ | |
d7e09d03 | 265 | for (;;) { |
480f40de | 266 | struct kvec iov = { |
d7e09d03 PT |
267 | .iov_base = buffer, |
268 | .iov_len = nob | |
269 | }; | |
270 | struct msghdr msg = { | |
d7e09d03 PT |
271 | .msg_flags = (timeout == 0) ? MSG_DONTWAIT : 0 |
272 | }; | |
273 | ||
274 | if (timeout != 0) { | |
275 | /* Set send timeout to remaining time */ | |
276 | tv = (struct timeval) { | |
277 | .tv_sec = ticks / HZ, | |
278 | .tv_usec = ((ticks % HZ) * 1000000) / HZ | |
279 | }; | |
80db2734 | 280 | rc = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, |
73092892 | 281 | (char *)&tv, sizeof(tv)); |
d7e09d03 | 282 | if (rc != 0) { |
2d00bd17 | 283 | CERROR("Can't set socket send timeout %ld.%06d: %d\n", |
d7e09d03 PT |
284 | (long)tv.tv_sec, (int)tv.tv_usec, rc); |
285 | return rc; | |
286 | } | |
287 | } | |
288 | ||
d7e09d03 | 289 | then = jiffies; |
480f40de | 290 | rc = kernel_sendmsg(sock, &msg, &iov, 1, nob); |
d7e09d03 | 291 | ticks -= jiffies - then; |
d7e09d03 PT |
292 | |
293 | if (rc == nob) | |
294 | return 0; | |
295 | ||
296 | if (rc < 0) | |
297 | return rc; | |
298 | ||
299 | if (rc == 0) { | |
73092892 | 300 | CERROR("Unexpected zero rc\n"); |
fbe7c6c7 | 301 | return -ECONNABORTED; |
d7e09d03 PT |
302 | } |
303 | ||
304 | if (ticks <= 0) | |
305 | return -EAGAIN; | |
306 | ||
307 | buffer = ((char *)buffer) + rc; | |
308 | nob -= rc; | |
309 | } | |
fbe7c6c7 | 310 | return 0; |
d7e09d03 | 311 | } |
1ad6a73e | 312 | EXPORT_SYMBOL(lnet_sock_write); |
d7e09d03 PT |
313 | |
314 | int | |
73092892 | 315 | lnet_sock_read(struct socket *sock, void *buffer, int nob, int timeout) |
d7e09d03 | 316 | { |
73092892 JS |
317 | int rc; |
318 | long ticks = timeout * HZ; | |
319 | unsigned long then; | |
d7e09d03 PT |
320 | struct timeval tv; |
321 | ||
73092892 JS |
322 | LASSERT(nob > 0); |
323 | LASSERT(ticks > 0); | |
d7e09d03 PT |
324 | |
325 | for (;;) { | |
b2f42cfe | 326 | struct kvec iov = { |
d7e09d03 PT |
327 | .iov_base = buffer, |
328 | .iov_len = nob | |
329 | }; | |
330 | struct msghdr msg = { | |
73092892 | 331 | .msg_flags = 0 |
d7e09d03 PT |
332 | }; |
333 | ||
334 | /* Set receive timeout to remaining time */ | |
335 | tv = (struct timeval) { | |
336 | .tv_sec = ticks / HZ, | |
337 | .tv_usec = ((ticks % HZ) * 1000000) / HZ | |
338 | }; | |
80db2734 | 339 | rc = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, |
73092892 | 340 | (char *)&tv, sizeof(tv)); |
d7e09d03 PT |
341 | if (rc != 0) { |
342 | CERROR("Can't set socket recv timeout %ld.%06d: %d\n", | |
343 | (long)tv.tv_sec, (int)tv.tv_usec, rc); | |
344 | return rc; | |
345 | } | |
346 | ||
d7e09d03 | 347 | then = jiffies; |
b2f42cfe | 348 | rc = kernel_recvmsg(sock, &msg, &iov, 1, nob, 0); |
d7e09d03 | 349 | ticks -= jiffies - then; |
d7e09d03 PT |
350 | |
351 | if (rc < 0) | |
352 | return rc; | |
353 | ||
354 | if (rc == 0) | |
355 | return -ECONNRESET; | |
356 | ||
357 | buffer = ((char *)buffer) + rc; | |
358 | nob -= rc; | |
359 | ||
360 | if (nob == 0) | |
361 | return 0; | |
362 | ||
363 | if (ticks <= 0) | |
364 | return -ETIMEDOUT; | |
365 | } | |
366 | } | |
1ad6a73e | 367 | EXPORT_SYMBOL(lnet_sock_read); |
d7e09d03 PT |
368 | |
369 | static int | |
73092892 JS |
370 | lnet_sock_create(struct socket **sockp, int *fatal, __u32 local_ip, |
371 | int local_port) | |
d7e09d03 | 372 | { |
73092892 JS |
373 | struct sockaddr_in locaddr; |
374 | struct socket *sock; | |
375 | int rc; | |
376 | int option; | |
d7e09d03 PT |
377 | |
378 | /* All errors are fatal except bind failure if the port is in use */ | |
379 | *fatal = 1; | |
380 | ||
73092892 | 381 | rc = sock_create(PF_INET, SOCK_STREAM, 0, &sock); |
d7e09d03 PT |
382 | *sockp = sock; |
383 | if (rc != 0) { | |
73092892 | 384 | CERROR("Can't create socket: %d\n", rc); |
fbe7c6c7 | 385 | return rc; |
d7e09d03 PT |
386 | } |
387 | ||
d7e09d03 | 388 | option = 1; |
80db2734 | 389 | rc = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, |
73092892 | 390 | (char *)&option, sizeof(option)); |
d7e09d03 PT |
391 | if (rc != 0) { |
392 | CERROR("Can't set SO_REUSEADDR for socket: %d\n", rc); | |
393 | goto failed; | |
394 | } | |
395 | ||
396 | if (local_ip != 0 || local_port != 0) { | |
397 | memset(&locaddr, 0, sizeof(locaddr)); | |
398 | locaddr.sin_family = AF_INET; | |
399 | locaddr.sin_port = htons(local_port); | |
400 | locaddr.sin_addr.s_addr = (local_ip == 0) ? | |
401 | INADDR_ANY : htonl(local_ip); | |
402 | ||
5c2414ef JS |
403 | rc = kernel_bind(sock, (struct sockaddr *)&locaddr, |
404 | sizeof(locaddr)); | |
d7e09d03 PT |
405 | if (rc == -EADDRINUSE) { |
406 | CDEBUG(D_NET, "Port %d already in use\n", local_port); | |
407 | *fatal = 0; | |
408 | goto failed; | |
409 | } | |
410 | if (rc != 0) { | |
411 | CERROR("Error trying to bind to port %d: %d\n", | |
412 | local_port, rc); | |
413 | goto failed; | |
414 | } | |
415 | } | |
d7e09d03 PT |
416 | return 0; |
417 | ||
73092892 | 418 | failed: |
d7e09d03 PT |
419 | sock_release(sock); |
420 | return rc; | |
421 | } | |
422 | ||
423 | int | |
73092892 | 424 | lnet_sock_setbuf(struct socket *sock, int txbufsize, int rxbufsize) |
d7e09d03 | 425 | { |
73092892 JS |
426 | int option; |
427 | int rc; | |
d7e09d03 PT |
428 | |
429 | if (txbufsize != 0) { | |
430 | option = txbufsize; | |
80db2734 | 431 | rc = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDBUF, |
73092892 | 432 | (char *)&option, sizeof(option)); |
d7e09d03 | 433 | if (rc != 0) { |
73092892 JS |
434 | CERROR("Can't set send buffer %d: %d\n", |
435 | option, rc); | |
fbe7c6c7 | 436 | return rc; |
d7e09d03 PT |
437 | } |
438 | } | |
439 | ||
440 | if (rxbufsize != 0) { | |
441 | option = rxbufsize; | |
80db2734 | 442 | rc = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUF, |
c314c319 | 443 | (char *)&option, sizeof(option)); |
d7e09d03 | 444 | if (rc != 0) { |
73092892 JS |
445 | CERROR("Can't set receive buffer %d: %d\n", |
446 | option, rc); | |
fbe7c6c7 | 447 | return rc; |
d7e09d03 PT |
448 | } |
449 | } | |
d7e09d03 PT |
450 | return 0; |
451 | } | |
1ad6a73e | 452 | EXPORT_SYMBOL(lnet_sock_setbuf); |
d7e09d03 PT |
453 | |
454 | int | |
73092892 | 455 | lnet_sock_getaddr(struct socket *sock, bool remote, __u32 *ip, int *port) |
d7e09d03 PT |
456 | { |
457 | struct sockaddr_in sin; | |
73092892 JS |
458 | int len = sizeof(sin); |
459 | int rc; | |
d7e09d03 | 460 | |
5c2414ef JS |
461 | if (remote) |
462 | rc = kernel_getpeername(sock, (struct sockaddr *)&sin, &len); | |
463 | else | |
464 | rc = kernel_getsockname(sock, (struct sockaddr *)&sin, &len); | |
d7e09d03 | 465 | if (rc != 0) { |
73092892 JS |
466 | CERROR("Error %d getting sock %s IP/port\n", |
467 | rc, remote ? "peer" : "local"); | |
d7e09d03 PT |
468 | return rc; |
469 | } | |
470 | ||
471 | if (ip != NULL) | |
73092892 | 472 | *ip = ntohl(sin.sin_addr.s_addr); |
d7e09d03 PT |
473 | |
474 | if (port != NULL) | |
73092892 | 475 | *port = ntohs(sin.sin_port); |
d7e09d03 PT |
476 | |
477 | return 0; | |
478 | } | |
1ad6a73e | 479 | EXPORT_SYMBOL(lnet_sock_getaddr); |
d7e09d03 PT |
480 | |
481 | int | |
73092892 | 482 | lnet_sock_getbuf(struct socket *sock, int *txbufsize, int *rxbufsize) |
d7e09d03 | 483 | { |
73092892 | 484 | if (txbufsize != NULL) |
d7e09d03 | 485 | *txbufsize = sock->sk->sk_sndbuf; |
d7e09d03 | 486 | |
73092892 | 487 | if (rxbufsize != NULL) |
d7e09d03 | 488 | *rxbufsize = sock->sk->sk_rcvbuf; |
d7e09d03 PT |
489 | |
490 | return 0; | |
491 | } | |
1ad6a73e | 492 | EXPORT_SYMBOL(lnet_sock_getbuf); |
d7e09d03 PT |
493 | |
494 | int | |
73092892 JS |
495 | lnet_sock_listen(struct socket **sockp, __u32 local_ip, int local_port, |
496 | int backlog) | |
d7e09d03 | 497 | { |
73092892 JS |
498 | int fatal; |
499 | int rc; | |
d7e09d03 | 500 | |
1ad6a73e | 501 | rc = lnet_sock_create(sockp, &fatal, local_ip, local_port); |
d7e09d03 PT |
502 | if (rc != 0) { |
503 | if (!fatal) | |
504 | CERROR("Can't create socket: port %d already in use\n", | |
505 | local_port); | |
506 | return rc; | |
507 | } | |
508 | ||
5c2414ef | 509 | rc = kernel_listen(*sockp, backlog); |
d7e09d03 PT |
510 | if (rc == 0) |
511 | return 0; | |
512 | ||
513 | CERROR("Can't set listen backlog %d: %d\n", backlog, rc); | |
514 | sock_release(*sockp); | |
515 | return rc; | |
516 | } | |
1ad6a73e | 517 | EXPORT_SYMBOL(lnet_sock_listen); |
d7e09d03 PT |
518 | |
519 | int | |
73092892 | 520 | lnet_sock_accept(struct socket **newsockp, struct socket *sock) |
d7e09d03 | 521 | { |
73092892 | 522 | wait_queue_t wait; |
d7e09d03 | 523 | struct socket *newsock; |
73092892 | 524 | int rc; |
d7e09d03 PT |
525 | |
526 | init_waitqueue_entry(&wait, current); | |
527 | ||
4420cfd3 JS |
528 | /* |
529 | * XXX this should add a ref to sock->ops->owner, if | |
530 | * TCP could be a module | |
531 | */ | |
d7e09d03 PT |
532 | rc = sock_create_lite(PF_PACKET, sock->type, IPPROTO_TCP, &newsock); |
533 | if (rc) { | |
534 | CERROR("Can't allocate socket\n"); | |
535 | return rc; | |
536 | } | |
537 | ||
538 | newsock->ops = sock->ops; | |
539 | ||
d7e09d03 PT |
540 | rc = sock->ops->accept(sock, newsock, O_NONBLOCK); |
541 | if (rc == -EAGAIN) { | |
542 | /* Nothing ready, so wait for activity */ | |
834fe2e1 OD |
543 | set_current_state(TASK_INTERRUPTIBLE); |
544 | add_wait_queue(sk_sleep(sock->sk), &wait); | |
d7e09d03 | 545 | schedule(); |
834fe2e1 OD |
546 | remove_wait_queue(sk_sleep(sock->sk), &wait); |
547 | set_current_state(TASK_RUNNING); | |
d7e09d03 PT |
548 | rc = sock->ops->accept(sock, newsock, O_NONBLOCK); |
549 | } | |
550 | ||
d7e09d03 PT |
551 | if (rc != 0) |
552 | goto failed; | |
553 | ||
554 | *newsockp = newsock; | |
555 | return 0; | |
556 | ||
73092892 | 557 | failed: |
d7e09d03 PT |
558 | sock_release(newsock); |
559 | return rc; | |
560 | } | |
1ad6a73e | 561 | EXPORT_SYMBOL(lnet_sock_accept); |
d7e09d03 | 562 | |
d7e09d03 | 563 | int |
73092892 JS |
564 | lnet_sock_connect(struct socket **sockp, int *fatal, __u32 local_ip, |
565 | int local_port, __u32 peer_ip, int peer_port) | |
d7e09d03 | 566 | { |
73092892 JS |
567 | struct sockaddr_in srvaddr; |
568 | int rc; | |
d7e09d03 | 569 | |
1ad6a73e | 570 | rc = lnet_sock_create(sockp, fatal, local_ip, local_port); |
d7e09d03 PT |
571 | if (rc != 0) |
572 | return rc; | |
573 | ||
73092892 | 574 | memset(&srvaddr, 0, sizeof(srvaddr)); |
d7e09d03 PT |
575 | srvaddr.sin_family = AF_INET; |
576 | srvaddr.sin_port = htons(peer_port); | |
577 | srvaddr.sin_addr.s_addr = htonl(peer_ip); | |
578 | ||
5c2414ef JS |
579 | rc = kernel_connect(*sockp, (struct sockaddr *)&srvaddr, |
580 | sizeof(srvaddr), 0); | |
d7e09d03 PT |
581 | if (rc == 0) |
582 | return 0; | |
583 | ||
4420cfd3 JS |
584 | /* |
585 | * EADDRNOTAVAIL probably means we're already connected to the same | |
d7e09d03 PT |
586 | * peer/port on the same local port on a differently typed |
587 | * connection. Let our caller retry with a different local | |
4420cfd3 JS |
588 | * port... |
589 | */ | |
d7e09d03 PT |
590 | *fatal = !(rc == -EADDRNOTAVAIL); |
591 | ||
592 | CDEBUG_LIMIT(*fatal ? D_NETERROR : D_NET, | |
73092892 JS |
593 | "Error %d connecting %pI4h/%d -> %pI4h/%d\n", rc, |
594 | &local_ip, local_port, &peer_ip, peer_port); | |
d7e09d03 PT |
595 | |
596 | sock_release(*sockp); | |
597 | return rc; | |
598 | } | |
1ad6a73e | 599 | EXPORT_SYMBOL(lnet_sock_connect); |