Blame view
net/tipc/socket.c
51.9 KB
b97bf3fd8
|
1 |
/* |
02c00c2ab
|
2 |
* net/tipc/socket.c: TIPC socket API |
c43072852
|
3 |
* |
8826cde65
|
4 |
* Copyright (c) 2001-2007, 2012-2014, Ericsson AB |
c5fa7b3cf
|
5 |
* Copyright (c) 2004-2008, 2010-2013, Wind River Systems |
b97bf3fd8
|
6 7 |
* All rights reserved. * |
9ea1fd3c1
|
8 |
* Redistribution and use in source and binary forms, with or without |
b97bf3fd8
|
9 10 |
* modification, are permitted provided that the following conditions are met: * |
9ea1fd3c1
|
11 12 13 14 15 16 17 18 |
* 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. |
b97bf3fd8
|
19 |
* |
9ea1fd3c1
|
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
* Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
b97bf3fd8
|
34 35 |
* POSSIBILITY OF SUCH DAMAGE. */ |
b97bf3fd8
|
36 |
#include "core.h" |
d265fef6d
|
37 |
#include "port.h" |
78acb1f9b
|
38 |
#include "node.h" |
b97bf3fd8
|
39 |
|
2cf8aa19f
|
40 |
#include <linux/export.h> |
8db1bae30
|
41 |
#include "link.h" |
2cf8aa19f
|
42 |
|
b97bf3fd8
|
43 44 |
#define SS_LISTENING -1 /* socket is listening */ #define SS_READY -2 /* socket is connectionless */ |
3654ea02f
|
45 |
#define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ |
b97bf3fd8
|
46 |
|
4f4482dcd
|
47 |
static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb); |
676d23690
|
48 |
static void tipc_data_ready(struct sock *sk); |
f288bef46
|
49 |
static void tipc_write_space(struct sock *sk); |
247f0f3c3
|
50 51 |
static int tipc_release(struct socket *sock); static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags); |
b97bf3fd8
|
52 |
|
bca65eae3
|
53 54 55 |
static const struct proto_ops packet_ops; static const struct proto_ops stream_ops; static const struct proto_ops msg_ops; |
b97bf3fd8
|
56 57 |
static struct proto tipc_proto; |
c5fa7b3cf
|
58 |
static struct proto tipc_proto_kern; |
b97bf3fd8
|
59 |
|
c43072852
|
60 |
/* |
0c3141e91
|
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
* Revised TIPC socket locking policy: * * Most socket operations take the standard socket lock when they start * and hold it until they finish (or until they need to sleep). Acquiring * this lock grants the owner exclusive access to the fields of the socket * data structures, with the exception of the backlog queue. A few socket * operations can be done without taking the socket lock because they only * read socket information that never changes during the life of the socket. * * Socket operations may acquire the lock for the associated TIPC port if they * need to perform an operation on the port. If any routine needs to acquire * both the socket lock and the port lock it must take the socket lock first * to avoid the risk of deadlock. * * The dispatcher handling incoming messages cannot grab the socket lock in * the standard fashion, since invoked it runs at the BH level and cannot block. * Instead, it checks to see if the socket lock is currently owned by someone, * and either handles the message itself or adds it to the socket's backlog * queue; in the latter case the queued message is processed once the process * owning the socket lock releases it. * * NOTE: Releasing the socket lock while an operation is sleeping overcomes * the problem of a blocked socket operation preventing any other operations * from occurring. However, applications must be careful if they have * multiple threads trying to send (or receive) on the same socket, as these * operations might interfere with each other. For example, doing a connect * and a receive at the same time might allow the receive to consume the * ACK message meant for the connect. While additional work could be done * to try and overcome this, it doesn't seem to be worthwhile at the present. * * NOTE: Releasing the socket lock while an operation is sleeping also ensures * that another operation that must be performed in a non-blocking manner is * not delayed for very long because the lock has already been taken. * * NOTE: This code assumes that certain fields of a port/socket pair are * constant over its lifetime; such fields can be examined without taking * the socket lock and/or port lock, and do not need to be re-read even * after resuming processing after waiting. These fields include: * - socket type * - pointer to socket sk structure (aka tipc_sock structure) * - pointer to port structure * - port reference */ |
8826cde65
|
104 |
#include "socket.h" |
0c3141e91
|
105 106 107 108 |
/** * advance_rx_queue - discard first buffer in socket receive queue * * Caller must hold socket lock |
b97bf3fd8
|
109 |
*/ |
0c3141e91
|
110 |
static void advance_rx_queue(struct sock *sk) |
b97bf3fd8
|
111 |
{ |
5f6d9123f
|
112 |
kfree_skb(__skb_dequeue(&sk->sk_receive_queue)); |
b97bf3fd8
|
113 |
} |
0c3141e91
|
114 |
/** |
0c3141e91
|
115 116 117 |
* reject_rx_queue - reject all buffers in socket receive queue * * Caller must hold socket lock |
b97bf3fd8
|
118 |
*/ |
0c3141e91
|
119 |
static void reject_rx_queue(struct sock *sk) |
b97bf3fd8
|
120 |
{ |
0c3141e91
|
121 |
struct sk_buff *buf; |
8db1bae30
|
122 |
u32 dnode; |
0c3141e91
|
123 |
|
8db1bae30
|
124 125 126 127 |
while ((buf = __skb_dequeue(&sk->sk_receive_queue))) { if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) tipc_link_xmit2(buf, dnode, 0); } |
b97bf3fd8
|
128 129 130 |
} /** |
c5fa7b3cf
|
131 |
* tipc_sk_create - create a TIPC socket |
0c3141e91
|
132 |
* @net: network namespace (must be default network) |
b97bf3fd8
|
133 134 |
* @sock: pre-allocated socket structure * @protocol: protocol indicator (must be 0) |
3f378b684
|
135 |
* @kern: caused by kernel or by userspace? |
c43072852
|
136 |
* |
0c3141e91
|
137 138 |
* This routine creates additional data structures used by the TIPC socket, * initializes them, and links them together. |
b97bf3fd8
|
139 140 141 |
* * Returns 0 on success, errno otherwise */ |
58ed94424
|
142 143 |
static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, int kern) |
b97bf3fd8
|
144 |
{ |
0c3141e91
|
145 146 |
const struct proto_ops *ops; socket_state state; |
b97bf3fd8
|
147 |
struct sock *sk; |
58ed94424
|
148 149 150 |
struct tipc_sock *tsk; struct tipc_port *port; u32 ref; |
0c3141e91
|
151 152 |
/* Validate arguments */ |
b97bf3fd8
|
153 154 |
if (unlikely(protocol != 0)) return -EPROTONOSUPPORT; |
b97bf3fd8
|
155 156 |
switch (sock->type) { case SOCK_STREAM: |
0c3141e91
|
157 158 |
ops = &stream_ops; state = SS_UNCONNECTED; |
b97bf3fd8
|
159 160 |
break; case SOCK_SEQPACKET: |
0c3141e91
|
161 162 |
ops = &packet_ops; state = SS_UNCONNECTED; |
b97bf3fd8
|
163 164 |
break; case SOCK_DGRAM: |
b97bf3fd8
|
165 |
case SOCK_RDM: |
0c3141e91
|
166 167 |
ops = &msg_ops; state = SS_READY; |
b97bf3fd8
|
168 |
break; |
499786516
|
169 |
default: |
499786516
|
170 |
return -EPROTOTYPE; |
b97bf3fd8
|
171 |
} |
0c3141e91
|
172 |
/* Allocate socket's protocol area */ |
c5fa7b3cf
|
173 174 175 176 |
if (!kern) sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto); else sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto_kern); |
0c3141e91
|
177 |
if (sk == NULL) |
b97bf3fd8
|
178 |
return -ENOMEM; |
b97bf3fd8
|
179 |
|
58ed94424
|
180 181 182 183 184 185 186 |
tsk = tipc_sk(sk); port = &tsk->port; ref = tipc_port_init(port, TIPC_LOW_IMPORTANCE); if (!ref) { pr_warn("Socket registration failed, ref. table exhausted "); |
0c3141e91
|
187 188 189 |
sk_free(sk); return -ENOMEM; } |
b97bf3fd8
|
190 |
|
0c3141e91
|
191 |
/* Finish initializing socket data structures */ |
0c3141e91
|
192 193 |
sock->ops = ops; sock->state = state; |
b97bf3fd8
|
194 |
|
0c3141e91
|
195 |
sock_init_data(sock, sk); |
4f4482dcd
|
196 |
sk->sk_backlog_rcv = tipc_backlog_rcv; |
cc79dd1ba
|
197 |
sk->sk_rcvbuf = sysctl_tipc_rmem[1]; |
f288bef46
|
198 199 |
sk->sk_data_ready = tipc_data_ready; sk->sk_write_space = tipc_write_space; |
4f4482dcd
|
200 201 |
tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; atomic_set(&tsk->dupl_rcvcnt, 0); |
58ed94424
|
202 |
tipc_port_unlock(port); |
7ef43ebaa
|
203 |
|
0c3141e91
|
204 |
if (sock->state == SS_READY) { |
58ed94424
|
205 |
tipc_port_set_unreturnable(port, true); |
0c3141e91
|
206 |
if (sock->type == SOCK_DGRAM) |
58ed94424
|
207 |
tipc_port_set_unreliable(port, true); |
0c3141e91
|
208 |
} |
b97bf3fd8
|
209 210 211 212 |
return 0; } /** |
c5fa7b3cf
|
213 214 215 216 217 218 219 220 221 222 223 224 225 |
* tipc_sock_create_local - create TIPC socket from inside TIPC module * @type: socket type - SOCK_RDM or SOCK_SEQPACKET * * We cannot use sock_creat_kern here because it bumps module user count. * Since socket owner and creator is the same module we must make sure * that module count remains zero for module local sockets, otherwise * we cannot do rmmod. * * Returns 0 on success, errno otherwise */ int tipc_sock_create_local(int type, struct socket **res) { int rc; |
c5fa7b3cf
|
226 227 228 229 230 231 232 233 |
rc = sock_create_lite(AF_TIPC, type, 0, res); if (rc < 0) { pr_err("Failed to create kernel socket "); return rc; } tipc_sk_create(&init_net, *res, 0, 1); |
c5fa7b3cf
|
234 235 236 237 238 239 240 241 242 243 244 245 |
return 0; } /** * tipc_sock_release_local - release socket created by tipc_sock_create_local * @sock: the socket to be released. * * Module reference count is not incremented when such sockets are created, * so we must keep it from being decremented when they are released. */ void tipc_sock_release_local(struct socket *sock) { |
247f0f3c3
|
246 |
tipc_release(sock); |
c5fa7b3cf
|
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
sock->ops = NULL; sock_release(sock); } /** * tipc_sock_accept_local - accept a connection on a socket created * with tipc_sock_create_local. Use this function to avoid that * module reference count is inadvertently incremented. * * @sock: the accepting socket * @newsock: reference to the new socket to be created * @flags: socket flags */ int tipc_sock_accept_local(struct socket *sock, struct socket **newsock, |
ae8509c42
|
262 |
int flags) |
c5fa7b3cf
|
263 264 265 266 267 268 269 270 |
{ struct sock *sk = sock->sk; int ret; ret = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol, newsock); if (ret < 0) return ret; |
247f0f3c3
|
271 |
ret = tipc_accept(sock, *newsock, flags); |
c5fa7b3cf
|
272 273 274 275 276 277 278 279 280 |
if (ret < 0) { sock_release(*newsock); return ret; } (*newsock)->ops = sock->ops; return ret; } /** |
247f0f3c3
|
281 |
* tipc_release - destroy a TIPC socket |
b97bf3fd8
|
282 283 284 285 286 287 288 |
* @sock: socket to destroy * * This routine cleans up any messages that are still queued on the socket. * For DGRAM and RDM socket types, all queued messages are rejected. * For SEQPACKET and STREAM socket types, the first message is rejected * and any others are discarded. (If the first message on a STREAM socket * is partially-read, it is discarded and the next one is rejected instead.) |
c43072852
|
289 |
* |
b97bf3fd8
|
290 291 292 293 294 295 |
* NOTE: Rejected messages are not necessarily returned to the sender! They * are returned or discarded according to the "destination droppable" setting * specified for the message by the sender. * * Returns 0 on success, errno otherwise */ |
247f0f3c3
|
296 |
static int tipc_release(struct socket *sock) |
b97bf3fd8
|
297 |
{ |
b97bf3fd8
|
298 |
struct sock *sk = sock->sk; |
58ed94424
|
299 300 |
struct tipc_sock *tsk; struct tipc_port *port; |
b97bf3fd8
|
301 |
struct sk_buff *buf; |
8db1bae30
|
302 |
u32 dnode; |
b97bf3fd8
|
303 |
|
0c3141e91
|
304 305 306 307 |
/* * Exit if socket isn't fully initialized (occurs when a failed accept() * releases a pre-allocated child socket that was never used) */ |
0c3141e91
|
308 |
if (sk == NULL) |
b97bf3fd8
|
309 |
return 0; |
c43072852
|
310 |
|
58ed94424
|
311 312 |
tsk = tipc_sk(sk); port = &tsk->port; |
0c3141e91
|
313 314 315 316 317 318 |
lock_sock(sk); /* * Reject all unreceived messages, except on an active connection * (which disconnects locally & sends a 'FIN+' to peer) */ |
b97bf3fd8
|
319 |
while (sock->state != SS_DISCONNECTING) { |
0c3141e91
|
320 321 |
buf = __skb_dequeue(&sk->sk_receive_queue); if (buf == NULL) |
b97bf3fd8
|
322 |
break; |
406824320
|
323 |
if (TIPC_SKB_CB(buf)->handle != NULL) |
5f6d9123f
|
324 |
kfree_skb(buf); |
0c3141e91
|
325 326 327 328 |
else { if ((sock->state == SS_CONNECTING) || (sock->state == SS_CONNECTED)) { sock->state = SS_DISCONNECTING; |
58ed94424
|
329 |
tipc_port_disconnect(port->ref); |
0c3141e91
|
330 |
} |
8db1bae30
|
331 332 |
if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) tipc_link_xmit2(buf, dnode, 0); |
0c3141e91
|
333 |
} |
b97bf3fd8
|
334 |
} |
58ed94424
|
335 336 |
/* Destroy TIPC port; also disconnects an active connection and * sends a 'FIN-' to peer. |
0c3141e91
|
337 |
*/ |
58ed94424
|
338 |
tipc_port_destroy(port); |
b97bf3fd8
|
339 |
|
0c3141e91
|
340 |
/* Discard any remaining (connection-based) messages in receive queue */ |
57467e562
|
341 |
__skb_queue_purge(&sk->sk_receive_queue); |
b97bf3fd8
|
342 |
|
0c3141e91
|
343 |
/* Reject any messages that accumulated in backlog queue */ |
0c3141e91
|
344 345 |
sock->state = SS_DISCONNECTING; release_sock(sk); |
b97bf3fd8
|
346 347 |
sock_put(sk); |
0c3141e91
|
348 |
sock->sk = NULL; |
b97bf3fd8
|
349 |
|
065d7e395
|
350 |
return 0; |
b97bf3fd8
|
351 352 353 |
} /** |
247f0f3c3
|
354 |
* tipc_bind - associate or disassocate TIPC name(s) with a socket |
b97bf3fd8
|
355 356 357 |
* @sock: socket structure * @uaddr: socket address describing name(s) and desired operation * @uaddr_len: size of socket address data structure |
c43072852
|
358 |
* |
b97bf3fd8
|
359 360 361 |
* Name and name sequence binding is indicated using a positive scope value; * a negative scope value unbinds the specified name. Specifying no name * (i.e. a socket address length of 0) unbinds all names from the socket. |
c43072852
|
362 |
* |
b97bf3fd8
|
363 |
* Returns 0 on success, errno otherwise |
0c3141e91
|
364 365 366 |
* * NOTE: This routine doesn't need to take the socket lock since it doesn't * access any non-constant socket information. |
b97bf3fd8
|
367 |
*/ |
247f0f3c3
|
368 369 |
static int tipc_bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) |
b97bf3fd8
|
370 |
{ |
84602761c
|
371 |
struct sock *sk = sock->sk; |
b97bf3fd8
|
372 |
struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; |
58ed94424
|
373 |
struct tipc_sock *tsk = tipc_sk(sk); |
84602761c
|
374 |
int res = -EINVAL; |
b97bf3fd8
|
375 |
|
84602761c
|
376 377 |
lock_sock(sk); if (unlikely(!uaddr_len)) { |
58ed94424
|
378 |
res = tipc_withdraw(&tsk->port, 0, NULL); |
84602761c
|
379 380 |
goto exit; } |
c43072852
|
381 |
|
84602761c
|
382 383 384 385 386 387 388 389 |
if (uaddr_len < sizeof(struct sockaddr_tipc)) { res = -EINVAL; goto exit; } if (addr->family != AF_TIPC) { res = -EAFNOSUPPORT; goto exit; } |
b97bf3fd8
|
390 |
|
b97bf3fd8
|
391 392 |
if (addr->addrtype == TIPC_ADDR_NAME) addr->addr.nameseq.upper = addr->addr.nameseq.lower; |
84602761c
|
393 394 395 396 |
else if (addr->addrtype != TIPC_ADDR_NAMESEQ) { res = -EAFNOSUPPORT; goto exit; } |
c43072852
|
397 |
|
13a2e8987
|
398 |
if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) && |
7d0ab17b7
|
399 |
(addr->addr.nameseq.type != TIPC_TOP_SRV) && |
84602761c
|
400 401 402 403 |
(addr->addr.nameseq.type != TIPC_CFG_SRV)) { res = -EACCES; goto exit; } |
c422f1bdc
|
404 |
|
84602761c
|
405 |
res = (addr->scope > 0) ? |
58ed94424
|
406 407 |
tipc_publish(&tsk->port, addr->scope, &addr->addr.nameseq) : tipc_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq); |
84602761c
|
408 409 410 |
exit: release_sock(sk); return res; |
b97bf3fd8
|
411 |
} |
c43072852
|
412 |
/** |
247f0f3c3
|
413 |
* tipc_getname - get port ID of socket or peer socket |
b97bf3fd8
|
414 415 416 |
* @sock: socket structure * @uaddr: area for returned socket address * @uaddr_len: area for returned length of socket address |
2da59918e
|
417 |
* @peer: 0 = own ID, 1 = current peer ID, 2 = current/former peer ID |
c43072852
|
418 |
* |
b97bf3fd8
|
419 |
* Returns 0 on success, errno otherwise |
0c3141e91
|
420 |
* |
2da59918e
|
421 422 |
* NOTE: This routine doesn't need to take the socket lock since it only * accesses socket information that is unchanging (or which changes in |
0e65967e3
|
423 |
* a completely predictable manner). |
b97bf3fd8
|
424 |
*/ |
247f0f3c3
|
425 426 |
static int tipc_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) |
b97bf3fd8
|
427 |
{ |
b97bf3fd8
|
428 |
struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; |
58ed94424
|
429 |
struct tipc_sock *tsk = tipc_sk(sock->sk); |
b97bf3fd8
|
430 |
|
88f8a5e3e
|
431 |
memset(addr, 0, sizeof(*addr)); |
0c3141e91
|
432 |
if (peer) { |
2da59918e
|
433 434 435 |
if ((sock->state != SS_CONNECTED) && ((peer != 2) || (sock->state != SS_DISCONNECTING))) return -ENOTCONN; |
58ed94424
|
436 437 |
addr->addr.id.ref = tipc_port_peerport(&tsk->port); addr->addr.id.node = tipc_port_peernode(&tsk->port); |
0c3141e91
|
438 |
} else { |
58ed94424
|
439 |
addr->addr.id.ref = tsk->port.ref; |
b924dcf00
|
440 |
addr->addr.id.node = tipc_own_addr; |
0c3141e91
|
441 |
} |
b97bf3fd8
|
442 443 444 445 446 |
*uaddr_len = sizeof(*addr); addr->addrtype = TIPC_ADDR_ID; addr->family = AF_TIPC; addr->scope = 0; |
b97bf3fd8
|
447 |
addr->addr.name.domain = 0; |
0c3141e91
|
448 |
return 0; |
b97bf3fd8
|
449 450 451 |
} /** |
247f0f3c3
|
452 |
* tipc_poll - read and possibly block on pollmask |
b97bf3fd8
|
453 454 455 456 |
* @file: file structure associated with the socket * @sock: socket for which to calculate the poll bits * @wait: ??? * |
9b674e82b
|
457 458 459 460 461 462 463 464 465 |
* Returns pollmask value * * COMMENTARY: * It appears that the usual socket locking mechanisms are not useful here * since the pollmask info is potentially out-of-date the moment this routine * exits. TCP and other protocols seem to rely on higher level poll routines * to handle any preventable race conditions, so TIPC will do the same ... * * TIPC sets the returned events as follows: |
f662c0705
|
466 467 468 469 |
* * socket state flags set * ------------ --------- * unconnected no read flags |
c4fc298ab
|
470 |
* POLLOUT if port is not congested |
f662c0705
|
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 |
* * connecting POLLIN/POLLRDNORM if ACK/NACK in rx queue * no write flags * * connected POLLIN/POLLRDNORM if data in rx queue * POLLOUT if port is not congested * * disconnecting POLLIN/POLLRDNORM/POLLHUP * no write flags * * listening POLLIN if SYN in rx queue * no write flags * * ready POLLIN/POLLRDNORM if data in rx queue * [connectionless] POLLOUT (since port cannot be congested) * * IMPORTANT: The fact that a read or write operation is indicated does NOT * imply that the operation will succeed, merely that it should be performed * and will not block. |
b97bf3fd8
|
490 |
*/ |
247f0f3c3
|
491 492 |
static unsigned int tipc_poll(struct file *file, struct socket *sock, poll_table *wait) |
b97bf3fd8
|
493 |
{ |
9b674e82b
|
494 |
struct sock *sk = sock->sk; |
58ed94424
|
495 |
struct tipc_sock *tsk = tipc_sk(sk); |
f662c0705
|
496 |
u32 mask = 0; |
9b674e82b
|
497 |
|
f288bef46
|
498 |
sock_poll_wait(file, sk_sleep(sk), wait); |
9b674e82b
|
499 |
|
f662c0705
|
500 |
switch ((int)sock->state) { |
c4fc298ab
|
501 |
case SS_UNCONNECTED: |
58ed94424
|
502 |
if (!tsk->port.congested) |
c4fc298ab
|
503 504 |
mask |= POLLOUT; break; |
f662c0705
|
505 506 |
case SS_READY: case SS_CONNECTED: |
58ed94424
|
507 |
if (!tsk->port.congested) |
f662c0705
|
508 509 510 511 512 513 514 515 516 517 518 |
mask |= POLLOUT; /* fall thru' */ case SS_CONNECTING: case SS_LISTENING: if (!skb_queue_empty(&sk->sk_receive_queue)) mask |= (POLLIN | POLLRDNORM); break; case SS_DISCONNECTING: mask = (POLLIN | POLLRDNORM | POLLHUP); break; } |
9b674e82b
|
519 520 |
return mask; |
b97bf3fd8
|
521 |
} |
c43072852
|
522 |
/** |
b97bf3fd8
|
523 524 525 |
* dest_name_check - verify user is permitted to send to specified port name * @dest: destination address * @m: descriptor for message to be sent |
c43072852
|
526 |
* |
b97bf3fd8
|
527 528 |
* Prevents restricted configuration commands from being issued by * unauthorized users. |
c43072852
|
529 |
* |
b97bf3fd8
|
530 531 |
* Returns 0 if permission is granted, otherwise errno */ |
05790c645
|
532 |
static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) |
b97bf3fd8
|
533 534 |
{ struct tipc_cfg_msg_hdr hdr; |
c43072852
|
535 536 537 538 |
if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES)) return 0; if (likely(dest->addr.name.name.type == TIPC_TOP_SRV)) return 0; |
c43072852
|
539 540 |
if (likely(dest->addr.name.name.type != TIPC_CFG_SRV)) return -EACCES; |
b97bf3fd8
|
541 |
|
3f8dd9446
|
542 543 |
if (!m->msg_iovlen || (m->msg_iov[0].iov_len < sizeof(hdr))) return -EMSGSIZE; |
c43072852
|
544 |
if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr))) |
b97bf3fd8
|
545 |
return -EFAULT; |
70cb23477
|
546 |
if ((ntohs(hdr.tcm_type) & 0xC000) && (!capable(CAP_NET_ADMIN))) |
b97bf3fd8
|
547 |
return -EACCES; |
c43072852
|
548 |
|
b97bf3fd8
|
549 550 |
return 0; } |
3f40504f7
|
551 552 553 |
static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) { struct sock *sk = sock->sk; |
58ed94424
|
554 |
struct tipc_sock *tsk = tipc_sk(sk); |
3f40504f7
|
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 |
DEFINE_WAIT(wait); int done; do { int err = sock_error(sk); if (err) return err; if (sock->state == SS_DISCONNECTING) return -EPIPE; if (!*timeo_p) return -EAGAIN; if (signal_pending(current)) return sock_intr_errno(*timeo_p); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
58ed94424
|
570 |
done = sk_wait_event(sk, timeo_p, !tsk->port.congested); |
3f40504f7
|
571 572 573 574 |
finish_wait(sk_sleep(sk), &wait); } while (!done); return 0; } |
58ed94424
|
575 |
|
b97bf3fd8
|
576 |
/** |
247f0f3c3
|
577 |
* tipc_sendmsg - send message in connectionless manner |
0c3141e91
|
578 |
* @iocb: if NULL, indicates that socket lock is already held |
b97bf3fd8
|
579 580 |
* @sock: socket structure * @m: message to send |
e9024f0f7
|
581 |
* @total_len: length of message |
c43072852
|
582 |
* |
b97bf3fd8
|
583 |
* Message must have an destination specified explicitly. |
c43072852
|
584 |
* Used for SOCK_RDM and SOCK_DGRAM messages, |
b97bf3fd8
|
585 586 |
* and for 'SYN' messages on SOCK_SEQPACKET and SOCK_STREAM connections. * (Note: 'SYN+' is prohibited on SOCK_STREAM.) |
c43072852
|
587 |
* |
b97bf3fd8
|
588 589 |
* Returns the number of bytes sent on success, or errno otherwise */ |
247f0f3c3
|
590 591 |
static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) |
b97bf3fd8
|
592 |
{ |
0c3141e91
|
593 |
struct sock *sk = sock->sk; |
58ed94424
|
594 |
struct tipc_sock *tsk = tipc_sk(sk); |
5c311421a
|
595 |
struct tipc_port *port = &tsk->port; |
342dfc306
|
596 |
DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
b97bf3fd8
|
597 |
int needs_conn; |
3f40504f7
|
598 |
long timeo; |
b97bf3fd8
|
599 600 601 602 |
int res = -EINVAL; if (unlikely(!dest)) return -EDESTADDRREQ; |
51f9cc1ff
|
603 604 |
if (unlikely((m->msg_namelen < sizeof(*dest)) || (dest->family != AF_TIPC))) |
b97bf3fd8
|
605 |
return -EINVAL; |
97f8b87e9
|
606 |
if (total_len > TIPC_MAX_USER_MSG_SIZE) |
c29c3f70c
|
607 |
return -EMSGSIZE; |
b97bf3fd8
|
608 |
|
0c3141e91
|
609 610 |
if (iocb) lock_sock(sk); |
b97bf3fd8
|
611 612 |
needs_conn = (sock->state != SS_READY); if (unlikely(needs_conn)) { |
0c3141e91
|
613 614 615 616 617 618 619 620 |
if (sock->state == SS_LISTENING) { res = -EPIPE; goto exit; } if (sock->state != SS_UNCONNECTED) { res = -EISCONN; goto exit; } |
58ed94424
|
621 |
if (tsk->port.published) { |
0c3141e91
|
622 623 624 |
res = -EOPNOTSUPP; goto exit; } |
3388007bc
|
625 |
if (dest->addrtype == TIPC_ADDR_NAME) { |
58ed94424
|
626 627 |
tsk->port.conn_type = dest->addr.name.name.type; tsk->port.conn_instance = dest->addr.name.name.instance; |
3388007bc
|
628 |
} |
b97bf3fd8
|
629 630 |
/* Abort any pending connection attempts (very unlikely) */ |
0c3141e91
|
631 |
reject_rx_queue(sk); |
b97bf3fd8
|
632 |
} |
3f40504f7
|
633 |
timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
c43072852
|
634 635 |
do { if (dest->addrtype == TIPC_ADDR_NAME) { |
2db9983a4
|
636 637 |
res = dest_name_check(dest, m); if (res) |
0c3141e91
|
638 |
break; |
5c311421a
|
639 |
res = tipc_send2name(port, |
c43072852
|
640 641 |
&dest->addr.name.name, dest->addr.name.domain, |
268969046
|
642 643 |
m->msg_iov, total_len); |
0e65967e3
|
644 |
} else if (dest->addrtype == TIPC_ADDR_ID) { |
5c311421a
|
645 |
res = tipc_send2port(port, |
c43072852
|
646 |
&dest->addr.id, |
268969046
|
647 648 |
m->msg_iov, total_len); |
0e65967e3
|
649 |
} else if (dest->addrtype == TIPC_ADDR_MCAST) { |
b97bf3fd8
|
650 651 |
if (needs_conn) { res = -EOPNOTSUPP; |
0c3141e91
|
652 |
break; |
b97bf3fd8
|
653 |
} |
2db9983a4
|
654 655 |
res = dest_name_check(dest, m); if (res) |
0c3141e91
|
656 |
break; |
5c311421a
|
657 |
res = tipc_port_mcast_xmit(port, |
247f0f3c3
|
658 659 660 |
&dest->addr.nameseq, m->msg_iov, total_len); |
c43072852
|
661 662 |
} if (likely(res != -ELINKCONG)) { |
a016892cd
|
663 |
if (needs_conn && (res >= 0)) |
0c3141e91
|
664 |
sock->state = SS_CONNECTING; |
0c3141e91
|
665 |
break; |
c43072852
|
666 |
} |
3f40504f7
|
667 668 |
res = tipc_wait_for_sndmsg(sock, &timeo); if (res) |
0c3141e91
|
669 |
break; |
c43072852
|
670 |
} while (1); |
0c3141e91
|
671 672 673 674 675 |
exit: if (iocb) release_sock(sk); return res; |
b97bf3fd8
|
676 |
} |
391a6dd1d
|
677 678 679 |
static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) { struct sock *sk = sock->sk; |
58ed94424
|
680 681 |
struct tipc_sock *tsk = tipc_sk(sk); struct tipc_port *port = &tsk->port; |
391a6dd1d
|
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 |
DEFINE_WAIT(wait); int done; do { int err = sock_error(sk); if (err) return err; if (sock->state == SS_DISCONNECTING) return -EPIPE; else if (sock->state != SS_CONNECTED) return -ENOTCONN; if (!*timeo_p) return -EAGAIN; if (signal_pending(current)) return sock_intr_errno(*timeo_p); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); done = sk_wait_event(sk, timeo_p, |
58ed94424
|
700 |
(!port->congested || !port->connected)); |
391a6dd1d
|
701 702 703 704 |
finish_wait(sk_sleep(sk), &wait); } while (!done); return 0; } |
c43072852
|
705 |
/** |
247f0f3c3
|
706 |
* tipc_send_packet - send a connection-oriented message |
0c3141e91
|
707 |
* @iocb: if NULL, indicates that socket lock is already held |
b97bf3fd8
|
708 709 |
* @sock: socket structure * @m: message to send |
e9024f0f7
|
710 |
* @total_len: length of message |
c43072852
|
711 |
* |
b97bf3fd8
|
712 |
* Used for SOCK_SEQPACKET messages and SOCK_STREAM data. |
c43072852
|
713 |
* |
b97bf3fd8
|
714 715 |
* Returns the number of bytes sent on success, or errno otherwise */ |
247f0f3c3
|
716 717 |
static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) |
b97bf3fd8
|
718 |
{ |
0c3141e91
|
719 |
struct sock *sk = sock->sk; |
58ed94424
|
720 |
struct tipc_sock *tsk = tipc_sk(sk); |
342dfc306
|
721 |
DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
391a6dd1d
|
722 723 |
int res = -EINVAL; long timeo; |
b97bf3fd8
|
724 725 |
/* Handle implied connection establishment */ |
b97bf3fd8
|
726 |
if (unlikely(dest)) |
247f0f3c3
|
727 |
return tipc_sendmsg(iocb, sock, m, total_len); |
b97bf3fd8
|
728 |
|
97f8b87e9
|
729 |
if (total_len > TIPC_MAX_USER_MSG_SIZE) |
c29c3f70c
|
730 |
return -EMSGSIZE; |
0c3141e91
|
731 732 |
if (iocb) lock_sock(sk); |
b97bf3fd8
|
733 |
|
391a6dd1d
|
734 735 736 737 738 739 740 |
if (unlikely(sock->state != SS_CONNECTED)) { if (sock->state == SS_DISCONNECTING) res = -EPIPE; else res = -ENOTCONN; goto exit; } |
1d835874a
|
741 |
|
391a6dd1d
|
742 |
timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
c43072852
|
743 |
do { |
5c311421a
|
744 |
res = tipc_send(&tsk->port, m->msg_iov, total_len); |
a016892cd
|
745 |
if (likely(res != -ELINKCONG)) |
0c3141e91
|
746 |
break; |
391a6dd1d
|
747 748 |
res = tipc_wait_for_sndpkt(sock, &timeo); if (res) |
0c3141e91
|
749 |
break; |
c43072852
|
750 |
} while (1); |
391a6dd1d
|
751 |
exit: |
0c3141e91
|
752 753 754 |
if (iocb) release_sock(sk); return res; |
b97bf3fd8
|
755 |
} |
c43072852
|
756 |
/** |
247f0f3c3
|
757 |
* tipc_send_stream - send stream-oriented data |
b97bf3fd8
|
758 759 760 761 |
* @iocb: (unused) * @sock: socket structure * @m: data to send * @total_len: total length of data to be sent |
c43072852
|
762 |
* |
b97bf3fd8
|
763 |
* Used for SOCK_STREAM data. |
c43072852
|
764 765 |
* * Returns the number of bytes sent on success (or partial success), |
1303e8f17
|
766 |
* or errno if no data sent |
b97bf3fd8
|
767 |
*/ |
247f0f3c3
|
768 769 |
static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) |
b97bf3fd8
|
770 |
{ |
0c3141e91
|
771 |
struct sock *sk = sock->sk; |
58ed94424
|
772 |
struct tipc_sock *tsk = tipc_sk(sk); |
b97bf3fd8
|
773 774 775 776 777 |
struct msghdr my_msg; struct iovec my_iov; struct iovec *curr_iov; int curr_iovlen; char __user *curr_start; |
05646c911
|
778 |
u32 hdr_size; |
b97bf3fd8
|
779 780 |
int curr_left; int bytes_to_send; |
1303e8f17
|
781 |
int bytes_sent; |
b97bf3fd8
|
782 |
int res; |
c43072852
|
783 |
|
0c3141e91
|
784 |
lock_sock(sk); |
05646c911
|
785 |
/* Handle special cases where there is no connection */ |
c43072852
|
786 |
if (unlikely(sock->state != SS_CONNECTED)) { |
3b8401fe9
|
787 |
if (sock->state == SS_UNCONNECTED) |
247f0f3c3
|
788 |
res = tipc_send_packet(NULL, sock, m, total_len); |
b05559769
|
789 790 |
else res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN; |
3b8401fe9
|
791 |
goto exit; |
c43072852
|
792 |
} |
b97bf3fd8
|
793 |
|
0c3141e91
|
794 795 796 797 |
if (unlikely(m->msg_name)) { res = -EISCONN; goto exit; } |
eb5959c2b
|
798 |
|
97f8b87e9
|
799 |
if (total_len > (unsigned int)INT_MAX) { |
c29c3f70c
|
800 801 802 |
res = -EMSGSIZE; goto exit; } |
c43072852
|
803 |
/* |
b97bf3fd8
|
804 805 |
* Send each iovec entry using one or more messages * |
c43072852
|
806 |
* Note: This algorithm is good for the most likely case |
b97bf3fd8
|
807 808 809 |
* (i.e. one large iovec entry), but could be improved to pass sets * of small iovec entries into send_packet(). */ |
1303e8f17
|
810 811 |
curr_iov = m->msg_iov; curr_iovlen = m->msg_iovlen; |
b97bf3fd8
|
812 813 |
my_msg.msg_iov = &my_iov; my_msg.msg_iovlen = 1; |
eb5959c2b
|
814 815 |
my_msg.msg_flags = m->msg_flags; my_msg.msg_name = NULL; |
1303e8f17
|
816 |
bytes_sent = 0; |
b97bf3fd8
|
817 |
|
58ed94424
|
818 |
hdr_size = msg_hdr_sz(&tsk->port.phdr); |
05646c911
|
819 |
|
b97bf3fd8
|
820 821 822 823 824 |
while (curr_iovlen--) { curr_start = curr_iov->iov_base; curr_left = curr_iov->iov_len; while (curr_left) { |
58ed94424
|
825 |
bytes_to_send = tsk->port.max_pkt - hdr_size; |
05646c911
|
826 827 828 829 |
if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE) bytes_to_send = TIPC_MAX_USER_MSG_SIZE; if (curr_left < bytes_to_send) bytes_to_send = curr_left; |
b97bf3fd8
|
830 831 |
my_iov.iov_base = curr_start; my_iov.iov_len = bytes_to_send; |
247f0f3c3
|
832 833 |
res = tipc_send_packet(NULL, sock, &my_msg, bytes_to_send); |
2db9983a4
|
834 |
if (res < 0) { |
0c3141e91
|
835 |
if (bytes_sent) |
05646c911
|
836 |
res = bytes_sent; |
0c3141e91
|
837 |
goto exit; |
1303e8f17
|
838 |
} |
b97bf3fd8
|
839 840 |
curr_left -= bytes_to_send; curr_start += bytes_to_send; |
1303e8f17
|
841 |
bytes_sent += bytes_to_send; |
b97bf3fd8
|
842 843 844 845 |
} curr_iov++; } |
0c3141e91
|
846 847 848 849 |
res = bytes_sent; exit: release_sock(sk); return res; |
b97bf3fd8
|
850 851 852 853 |
} /** * auto_connect - complete connection setup to a remote port |
58ed94424
|
854 |
* @tsk: tipc socket structure |
b97bf3fd8
|
855 |
* @msg: peer's response message |
c43072852
|
856 |
* |
b97bf3fd8
|
857 858 |
* Returns 0 on success, errno otherwise */ |
58ed94424
|
859 |
static int auto_connect(struct tipc_sock *tsk, struct tipc_msg *msg) |
b97bf3fd8
|
860 |
{ |
58ed94424
|
861 862 |
struct tipc_port *port = &tsk->port; struct socket *sock = tsk->sk.sk_socket; |
f9fef18c6
|
863 864 865 866 |
struct tipc_portid peer; peer.ref = msg_origport(msg); peer.node = msg_orignode(msg); |
b97bf3fd8
|
867 |
|
58ed94424
|
868 |
__tipc_port_connect(port->ref, port, &peer); |
584d24b39
|
869 870 871 |
if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE) return -EINVAL; |
58ed94424
|
872 |
msg_set_importance(&port->phdr, (u32)msg_importance(msg)); |
b97bf3fd8
|
873 874 875 876 877 878 879 880 |
sock->state = SS_CONNECTED; return 0; } /** * set_orig_addr - capture sender's address for received message * @m: descriptor for message info * @msg: received message header |
c43072852
|
881 |
* |
b97bf3fd8
|
882 883 |
* Note: Address is not captured if not requested by receiver. */ |
05790c645
|
884 |
static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) |
b97bf3fd8
|
885 |
{ |
342dfc306
|
886 |
DECLARE_SOCKADDR(struct sockaddr_tipc *, addr, m->msg_name); |
b97bf3fd8
|
887 |
|
c43072852
|
888 |
if (addr) { |
b97bf3fd8
|
889 890 |
addr->family = AF_TIPC; addr->addrtype = TIPC_ADDR_ID; |
60085c3d0
|
891 |
memset(&addr->addr, 0, sizeof(addr->addr)); |
b97bf3fd8
|
892 893 |
addr->addr.id.ref = msg_origport(msg); addr->addr.id.node = msg_orignode(msg); |
0e65967e3
|
894 895 |
addr->addr.name.domain = 0; /* could leave uninitialized */ addr->scope = 0; /* could leave uninitialized */ |
b97bf3fd8
|
896 897 898 899 900 |
m->msg_namelen = sizeof(struct sockaddr_tipc); } } /** |
c43072852
|
901 |
* anc_data_recv - optionally capture ancillary data for received message |
b97bf3fd8
|
902 903 904 |
* @m: descriptor for message info * @msg: received message header * @tport: TIPC port associated with message |
c43072852
|
905 |
* |
b97bf3fd8
|
906 |
* Note: Ancillary data is not captured if not requested by receiver. |
c43072852
|
907 |
* |
b97bf3fd8
|
908 909 |
* Returns 0 if successful, otherwise errno */ |
05790c645
|
910 |
static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, |
ae8509c42
|
911 |
struct tipc_port *tport) |
b97bf3fd8
|
912 913 914 915 |
{ u32 anc_data[3]; u32 err; u32 dest_type; |
3546c7508
|
916 |
int has_name; |
b97bf3fd8
|
917 918 919 920 921 922 |
int res; if (likely(m->msg_controllen == 0)) return 0; /* Optionally capture errored message object(s) */ |
b97bf3fd8
|
923 924 925 926 |
err = msg ? msg_errcode(msg) : 0; if (unlikely(err)) { anc_data[0] = err; anc_data[1] = msg_data_sz(msg); |
2db9983a4
|
927 928 |
res = put_cmsg(m, SOL_TIPC, TIPC_ERRINFO, 8, anc_data); if (res) |
b97bf3fd8
|
929 |
return res; |
2db9983a4
|
930 931 932 933 934 935 |
if (anc_data[1]) { res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1], msg_data(msg)); if (res) return res; } |
b97bf3fd8
|
936 937 938 |
} /* Optionally capture message destination object */ |
b97bf3fd8
|
939 940 941 |
dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG; switch (dest_type) { case TIPC_NAMED_MSG: |
3546c7508
|
942 |
has_name = 1; |
b97bf3fd8
|
943 944 945 946 947 |
anc_data[0] = msg_nametype(msg); anc_data[1] = msg_namelower(msg); anc_data[2] = msg_namelower(msg); break; case TIPC_MCAST_MSG: |
3546c7508
|
948 |
has_name = 1; |
b97bf3fd8
|
949 950 951 952 953 |
anc_data[0] = msg_nametype(msg); anc_data[1] = msg_namelower(msg); anc_data[2] = msg_nameupper(msg); break; case TIPC_CONN_MSG: |
3546c7508
|
954 |
has_name = (tport->conn_type != 0); |
b97bf3fd8
|
955 956 957 958 959 |
anc_data[0] = tport->conn_type; anc_data[1] = tport->conn_instance; anc_data[2] = tport->conn_instance; break; default: |
3546c7508
|
960 |
has_name = 0; |
b97bf3fd8
|
961 |
} |
2db9983a4
|
962 963 964 965 966 |
if (has_name) { res = put_cmsg(m, SOL_TIPC, TIPC_DESTNAME, 12, anc_data); if (res) return res; } |
b97bf3fd8
|
967 968 969 |
return 0; } |
85d3fc941
|
970 |
static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) |
9bbb4ecc6
|
971 972 973 |
{ struct sock *sk = sock->sk; DEFINE_WAIT(wait); |
85d3fc941
|
974 |
long timeo = *timeop; |
9bbb4ecc6
|
975 976 977 978 |
int err; for (;;) { prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
fe8e46493
|
979 |
if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { |
9bbb4ecc6
|
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 |
if (sock->state == SS_DISCONNECTING) { err = -ENOTCONN; break; } release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); } err = 0; if (!skb_queue_empty(&sk->sk_receive_queue)) break; err = sock_intr_errno(timeo); if (signal_pending(current)) break; err = -EAGAIN; if (!timeo) break; } finish_wait(sk_sleep(sk), &wait); |
85d3fc941
|
999 |
*timeop = timeo; |
9bbb4ecc6
|
1000 1001 |
return err; } |
c43072852
|
1002 |
/** |
247f0f3c3
|
1003 |
* tipc_recvmsg - receive packet-oriented message |
b97bf3fd8
|
1004 1005 1006 1007 |
* @iocb: (unused) * @m: descriptor for message info * @buf_len: total size of user buffer area * @flags: receive flags |
c43072852
|
1008 |
* |
b97bf3fd8
|
1009 1010 1011 1012 1013 |
* Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages. * If the complete message doesn't fit in user area, truncate it. * * Returns size of returned message data, errno otherwise */ |
247f0f3c3
|
1014 1015 |
static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) |
b97bf3fd8
|
1016 |
{ |
0c3141e91
|
1017 |
struct sock *sk = sock->sk; |
58ed94424
|
1018 1019 |
struct tipc_sock *tsk = tipc_sk(sk); struct tipc_port *port = &tsk->port; |
b97bf3fd8
|
1020 1021 |
struct sk_buff *buf; struct tipc_msg *msg; |
9bbb4ecc6
|
1022 |
long timeo; |
b97bf3fd8
|
1023 1024 1025 |
unsigned int sz; u32 err; int res; |
0c3141e91
|
1026 |
/* Catch invalid receive requests */ |
b97bf3fd8
|
1027 1028 |
if (unlikely(!buf_len)) return -EINVAL; |
0c3141e91
|
1029 |
lock_sock(sk); |
b97bf3fd8
|
1030 |
|
0c3141e91
|
1031 1032 |
if (unlikely(sock->state == SS_UNCONNECTED)) { res = -ENOTCONN; |
b97bf3fd8
|
1033 1034 |
goto exit; } |
9bbb4ecc6
|
1035 |
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
0c3141e91
|
1036 |
restart: |
b97bf3fd8
|
1037 |
|
0c3141e91
|
1038 |
/* Look for a message in receive queue; wait if necessary */ |
85d3fc941
|
1039 |
res = tipc_wait_for_rcvmsg(sock, &timeo); |
9bbb4ecc6
|
1040 1041 |
if (res) goto exit; |
b97bf3fd8
|
1042 |
|
0c3141e91
|
1043 |
/* Look at first message in receive queue */ |
0c3141e91
|
1044 |
buf = skb_peek(&sk->sk_receive_queue); |
b97bf3fd8
|
1045 1046 1047 |
msg = buf_msg(buf); sz = msg_data_sz(msg); err = msg_errcode(msg); |
b97bf3fd8
|
1048 |
/* Discard an empty non-errored message & try again */ |
b97bf3fd8
|
1049 |
if ((!sz) && (!err)) { |
0c3141e91
|
1050 |
advance_rx_queue(sk); |
b97bf3fd8
|
1051 1052 1053 1054 |
goto restart; } /* Capture sender's address (optional) */ |
b97bf3fd8
|
1055 1056 1057 |
set_orig_addr(m, msg); /* Capture ancillary data (optional) */ |
58ed94424
|
1058 |
res = anc_data_recv(m, msg, port); |
0c3141e91
|
1059 |
if (res) |
b97bf3fd8
|
1060 1061 1062 |
goto exit; /* Capture message data (if valid) & compute return value (always) */ |
b97bf3fd8
|
1063 1064 1065 1066 1067 |
if (!err) { if (unlikely(buf_len < sz)) { sz = buf_len; m->msg_flags |= MSG_TRUNC; } |
0232fd0ac
|
1068 1069 1070 |
res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg), m->msg_iov, sz); if (res) |
b97bf3fd8
|
1071 |
goto exit; |
b97bf3fd8
|
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 |
res = sz; } else { if ((sock->state == SS_READY) || ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)) res = 0; else res = -ECONNRESET; } /* Consume received message (optional) */ |
b97bf3fd8
|
1082 |
if (likely(!(flags & MSG_PEEK))) { |
990098068
|
1083 |
if ((sock->state != SS_READY) && |
6163a194e
|
1084 |
(++port->conn_unacked >= TIPC_CONNACK_INTV)) |
58ed94424
|
1085 |
tipc_acknowledge(port->ref, port->conn_unacked); |
0c3141e91
|
1086 |
advance_rx_queue(sk); |
c43072852
|
1087 |
} |
b97bf3fd8
|
1088 |
exit: |
0c3141e91
|
1089 |
release_sock(sk); |
b97bf3fd8
|
1090 1091 |
return res; } |
c43072852
|
1092 |
/** |
247f0f3c3
|
1093 |
* tipc_recv_stream - receive stream-oriented data |
b97bf3fd8
|
1094 1095 1096 1097 |
* @iocb: (unused) * @m: descriptor for message info * @buf_len: total size of user buffer area * @flags: receive flags |
c43072852
|
1098 1099 |
* * Used for SOCK_STREAM messages only. If not enough data is available |
b97bf3fd8
|
1100 1101 1102 1103 |
* will optionally wait for more; never truncates data. * * Returns size of returned message data, errno otherwise */ |
247f0f3c3
|
1104 1105 |
static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) |
b97bf3fd8
|
1106 |
{ |
0c3141e91
|
1107 |
struct sock *sk = sock->sk; |
58ed94424
|
1108 1109 |
struct tipc_sock *tsk = tipc_sk(sk); struct tipc_port *port = &tsk->port; |
b97bf3fd8
|
1110 1111 |
struct sk_buff *buf; struct tipc_msg *msg; |
9bbb4ecc6
|
1112 |
long timeo; |
b97bf3fd8
|
1113 |
unsigned int sz; |
3720d40b2
|
1114 |
int sz_to_copy, target, needed; |
b97bf3fd8
|
1115 |
int sz_copied = 0; |
b97bf3fd8
|
1116 |
u32 err; |
0c3141e91
|
1117 |
int res = 0; |
b97bf3fd8
|
1118 |
|
0c3141e91
|
1119 |
/* Catch invalid receive attempts */ |
b97bf3fd8
|
1120 1121 |
if (unlikely(!buf_len)) return -EINVAL; |
0c3141e91
|
1122 |
lock_sock(sk); |
b97bf3fd8
|
1123 |
|
9bbb4ecc6
|
1124 |
if (unlikely(sock->state == SS_UNCONNECTED)) { |
0c3141e91
|
1125 |
res = -ENOTCONN; |
b97bf3fd8
|
1126 1127 |
goto exit; } |
3720d40b2
|
1128 |
target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); |
9bbb4ecc6
|
1129 |
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
b97bf3fd8
|
1130 |
|
617d3c7a5
|
1131 |
restart: |
0c3141e91
|
1132 |
/* Look for a message in receive queue; wait if necessary */ |
85d3fc941
|
1133 |
res = tipc_wait_for_rcvmsg(sock, &timeo); |
9bbb4ecc6
|
1134 1135 |
if (res) goto exit; |
b97bf3fd8
|
1136 |
|
0c3141e91
|
1137 |
/* Look at first message in receive queue */ |
0c3141e91
|
1138 |
buf = skb_peek(&sk->sk_receive_queue); |
b97bf3fd8
|
1139 1140 1141 1142 1143 |
msg = buf_msg(buf); sz = msg_data_sz(msg); err = msg_errcode(msg); /* Discard an empty non-errored message & try again */ |
b97bf3fd8
|
1144 |
if ((!sz) && (!err)) { |
0c3141e91
|
1145 |
advance_rx_queue(sk); |
b97bf3fd8
|
1146 1147 1148 1149 |
goto restart; } /* Optionally capture sender's address & ancillary data of first msg */ |
b97bf3fd8
|
1150 1151 |
if (sz_copied == 0) { set_orig_addr(m, msg); |
58ed94424
|
1152 |
res = anc_data_recv(m, msg, port); |
0c3141e91
|
1153 |
if (res) |
b97bf3fd8
|
1154 1155 1156 1157 |
goto exit; } /* Capture message data (if valid) & compute return value (always) */ |
b97bf3fd8
|
1158 |
if (!err) { |
0232fd0ac
|
1159 |
u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle); |
b97bf3fd8
|
1160 |
|
0232fd0ac
|
1161 |
sz -= offset; |
b97bf3fd8
|
1162 1163 |
needed = (buf_len - sz_copied); sz_to_copy = (sz <= needed) ? sz : needed; |
0232fd0ac
|
1164 1165 1166 1167 |
res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg) + offset, m->msg_iov, sz_to_copy); if (res) |
b97bf3fd8
|
1168 |
goto exit; |
0232fd0ac
|
1169 |
|
b97bf3fd8
|
1170 1171 1172 1173 |
sz_copied += sz_to_copy; if (sz_to_copy < sz) { if (!(flags & MSG_PEEK)) |
0232fd0ac
|
1174 1175 |
TIPC_SKB_CB(buf)->handle = (void *)(unsigned long)(offset + sz_to_copy); |
b97bf3fd8
|
1176 1177 |
goto exit; } |
b97bf3fd8
|
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
} else { if (sz_copied != 0) goto exit; /* can't add error msg to valid data */ if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control) res = 0; else res = -ECONNRESET; } /* Consume received message (optional) */ |
b97bf3fd8
|
1189 |
if (likely(!(flags & MSG_PEEK))) { |
6163a194e
|
1190 |
if (unlikely(++port->conn_unacked >= TIPC_CONNACK_INTV)) |
58ed94424
|
1191 |
tipc_acknowledge(port->ref, port->conn_unacked); |
0c3141e91
|
1192 |
advance_rx_queue(sk); |
c43072852
|
1193 |
} |
b97bf3fd8
|
1194 1195 |
/* Loop around if more data is required */ |
f64f9e719
|
1196 1197 |
if ((sz_copied < buf_len) && /* didn't get all requested data */ (!skb_queue_empty(&sk->sk_receive_queue) || |
3720d40b2
|
1198 |
(sz_copied < target)) && /* and more is ready or required */ |
f64f9e719
|
1199 1200 |
(!(flags & MSG_PEEK)) && /* and aren't just peeking at data */ (!err)) /* and haven't reached a FIN */ |
b97bf3fd8
|
1201 1202 1203 |
goto restart; exit: |
0c3141e91
|
1204 |
release_sock(sk); |
a3b0a5a9d
|
1205 |
return sz_copied ? sz_copied : res; |
b97bf3fd8
|
1206 1207 1208 |
} /** |
f288bef46
|
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 |
* tipc_write_space - wake up thread if port congestion is released * @sk: socket */ static void tipc_write_space(struct sock *sk) { struct socket_wq *wq; rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); if (wq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | POLLWRNORM | POLLWRBAND); rcu_read_unlock(); } /** * tipc_data_ready - wake up threads to indicate messages have been received * @sk: socket * @len: the length of messages */ |
676d23690
|
1229 |
static void tipc_data_ready(struct sock *sk) |
f288bef46
|
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 |
{ struct socket_wq *wq; rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); if (wq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLRDNORM | POLLRDBAND); rcu_read_unlock(); } /** |
7e6c131e1
|
1242 |
* filter_connect - Handle all incoming messages for a connection-based socket |
58ed94424
|
1243 |
* @tsk: TIPC socket |
7e6c131e1
|
1244 1245 |
* @msg: message * |
e4de5fab8
|
1246 |
* Returns 0 (TIPC_OK) if everyting ok, -TIPC_ERR_NO_PORT otherwise |
7e6c131e1
|
1247 |
*/ |
e4de5fab8
|
1248 |
static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf) |
7e6c131e1
|
1249 |
{ |
58ed94424
|
1250 1251 |
struct sock *sk = &tsk->sk; struct tipc_port *port = &tsk->port; |
8826cde65
|
1252 |
struct socket *sock = sk->sk_socket; |
7e6c131e1
|
1253 |
struct tipc_msg *msg = buf_msg(*buf); |
8826cde65
|
1254 |
|
e4de5fab8
|
1255 |
int retval = -TIPC_ERR_NO_PORT; |
584d24b39
|
1256 |
int res; |
7e6c131e1
|
1257 1258 1259 1260 1261 1262 1263 |
if (msg_mcast(msg)) return retval; switch ((int)sock->state) { case SS_CONNECTED: /* Accept only connection-based messages sent by peer */ |
8826cde65
|
1264 |
if (msg_connected(msg) && tipc_port_peer_msg(port, msg)) { |
7e6c131e1
|
1265 1266 |
if (unlikely(msg_errcode(msg))) { sock->state = SS_DISCONNECTING; |
8826cde65
|
1267 |
__tipc_port_disconnect(port); |
7e6c131e1
|
1268 1269 1270 1271 1272 1273 |
} retval = TIPC_OK; } break; case SS_CONNECTING: /* Accept only ACK or NACK message */ |
584d24b39
|
1274 1275 |
if (unlikely(msg_errcode(msg))) { sock->state = SS_DISCONNECTING; |
2c8d85182
|
1276 |
sk->sk_err = ECONNREFUSED; |
584d24b39
|
1277 1278 1279 1280 1281 1282 |
retval = TIPC_OK; break; } if (unlikely(!msg_connected(msg))) break; |
58ed94424
|
1283 |
res = auto_connect(tsk, msg); |
584d24b39
|
1284 1285 |
if (res) { sock->state = SS_DISCONNECTING; |
2c8d85182
|
1286 |
sk->sk_err = -res; |
7e6c131e1
|
1287 |
retval = TIPC_OK; |
584d24b39
|
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 |
break; } /* If an incoming message is an 'ACK-', it should be * discarded here because it doesn't contain useful * data. In addition, we should try to wake up * connect() routine if sleeping. */ if (msg_data_sz(msg) == 0) { kfree_skb(*buf); *buf = NULL; if (waitqueue_active(sk_sleep(sk))) wake_up_interruptible(sk_sleep(sk)); } retval = TIPC_OK; |
7e6c131e1
|
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 |
break; case SS_LISTENING: case SS_UNCONNECTED: /* Accept only SYN message */ if (!msg_connected(msg) && !(msg_errcode(msg))) retval = TIPC_OK; break; case SS_DISCONNECTING: break; default: pr_err("Unknown socket state %u ", sock->state); } return retval; } /** |
aba79f332
|
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 |
* rcvbuf_limit - get proper overload limit of socket receive queue * @sk: socket * @buf: message * * For all connection oriented messages, irrespective of importance, * the default overload value (i.e. 67MB) is set as limit. * * For all connectionless messages, by default new queue limits are * as belows: * |
cc79dd1ba
|
1330 1331 1332 1333 |
* TIPC_LOW_IMPORTANCE (4 MB) * TIPC_MEDIUM_IMPORTANCE (8 MB) * TIPC_HIGH_IMPORTANCE (16 MB) * TIPC_CRITICAL_IMPORTANCE (32 MB) |
aba79f332
|
1334 1335 1336 1337 1338 1339 |
* * Returns overload limit according to corresponding message importance */ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); |
aba79f332
|
1340 1341 |
if (msg_connected(msg)) |
0cee6bbe0
|
1342 1343 1344 1345 |
return sysctl_tipc_rmem[2]; return sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << msg_importance(msg); |
aba79f332
|
1346 1347 1348 |
} /** |
0c3141e91
|
1349 1350 |
* filter_rcv - validate incoming message * @sk: socket |
b97bf3fd8
|
1351 |
* @buf: message |
c43072852
|
1352 |
* |
0c3141e91
|
1353 1354 1355 1356 |
* Enqueues message on receive queue if acceptable; optionally handles * disconnect indication for a connected socket. * * Called with socket lock already taken; port lock may also be taken. |
c43072852
|
1357 |
* |
e4de5fab8
|
1358 1359 |
* Returns 0 (TIPC_OK) if message was consumed, -TIPC error code if message * to be rejected. |
b97bf3fd8
|
1360 |
*/ |
e4de5fab8
|
1361 |
static int filter_rcv(struct sock *sk, struct sk_buff *buf) |
b97bf3fd8
|
1362 |
{ |
0c3141e91
|
1363 |
struct socket *sock = sk->sk_socket; |
58ed94424
|
1364 |
struct tipc_sock *tsk = tipc_sk(sk); |
b97bf3fd8
|
1365 |
struct tipc_msg *msg = buf_msg(buf); |
aba79f332
|
1366 |
unsigned int limit = rcvbuf_limit(sk, buf); |
e4de5fab8
|
1367 |
int rc = TIPC_OK; |
b97bf3fd8
|
1368 |
|
b97bf3fd8
|
1369 |
/* Reject message if it is wrong sort of message for socket */ |
aad585473
|
1370 |
if (msg_type(msg) > TIPC_DIRECT_MSG) |
e4de5fab8
|
1371 |
return -TIPC_ERR_NO_PORT; |
0c3141e91
|
1372 |
|
b97bf3fd8
|
1373 |
if (sock->state == SS_READY) { |
b29f14284
|
1374 |
if (msg_connected(msg)) |
e4de5fab8
|
1375 |
return -TIPC_ERR_NO_PORT; |
b97bf3fd8
|
1376 |
} else { |
e4de5fab8
|
1377 1378 1379 |
rc = filter_connect(tsk, &buf); if (rc != TIPC_OK || buf == NULL) return rc; |
b97bf3fd8
|
1380 1381 1382 |
} /* Reject message if there isn't room to queue it */ |
aba79f332
|
1383 |
if (sk_rmem_alloc_get(sk) + buf->truesize >= limit) |
e4de5fab8
|
1384 |
return -TIPC_ERR_OVERLOAD; |
b97bf3fd8
|
1385 |
|
aba79f332
|
1386 |
/* Enqueue message */ |
406824320
|
1387 |
TIPC_SKB_CB(buf)->handle = NULL; |
0c3141e91
|
1388 |
__skb_queue_tail(&sk->sk_receive_queue, buf); |
aba79f332
|
1389 |
skb_set_owner_r(buf, sk); |
0c3141e91
|
1390 |
|
676d23690
|
1391 |
sk->sk_data_ready(sk); |
0c3141e91
|
1392 1393 |
return TIPC_OK; } |
b97bf3fd8
|
1394 |
|
0c3141e91
|
1395 |
/** |
4f4482dcd
|
1396 |
* tipc_backlog_rcv - handle incoming message from backlog queue |
0c3141e91
|
1397 1398 1399 1400 1401 1402 1403 |
* @sk: socket * @buf: message * * Caller must hold socket lock, but not port lock. * * Returns 0 */ |
4f4482dcd
|
1404 |
static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf) |
0c3141e91
|
1405 |
{ |
e4de5fab8
|
1406 |
int rc; |
8db1bae30
|
1407 |
u32 onode; |
4f4482dcd
|
1408 |
struct tipc_sock *tsk = tipc_sk(sk); |
02c00c2ab
|
1409 |
uint truesize = buf->truesize; |
0c3141e91
|
1410 |
|
e4de5fab8
|
1411 |
rc = filter_rcv(sk, buf); |
4f4482dcd
|
1412 |
|
8db1bae30
|
1413 1414 1415 |
if (unlikely(rc && tipc_msg_reverse(buf, &onode, -rc))) tipc_link_xmit2(buf, onode, 0); else if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) |
02c00c2ab
|
1416 |
atomic_add(truesize, &tsk->dupl_rcvcnt); |
4f4482dcd
|
1417 |
|
0c3141e91
|
1418 1419 1420 1421 |
return 0; } /** |
24be34b5a
|
1422 |
* tipc_sk_rcv - handle incoming message |
9816f0615
|
1423 1424 1425 |
* @buf: buffer containing arriving message * Consumes buffer * Returns 0 if success, or errno: -EHOSTUNREACH |
0c3141e91
|
1426 |
*/ |
9816f0615
|
1427 |
int tipc_sk_rcv(struct sk_buff *buf) |
0c3141e91
|
1428 |
{ |
9816f0615
|
1429 1430 1431 1432 |
struct tipc_sock *tsk; struct tipc_port *port; struct sock *sk; u32 dport = msg_destport(buf_msg(buf)); |
e4de5fab8
|
1433 |
int rc = TIPC_OK; |
4f4482dcd
|
1434 |
uint limit; |
8db1bae30
|
1435 |
u32 dnode; |
9816f0615
|
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 |
/* Forward unresolved named message */ if (unlikely(!dport)) { tipc_net_route_msg(buf); return 0; } /* Validate destination */ port = tipc_port_lock(dport); if (unlikely(!port)) { |
e4de5fab8
|
1446 |
rc = -TIPC_ERR_NO_PORT; |
9816f0615
|
1447 1448 1449 1450 1451 1452 1453 |
goto exit; } tsk = tipc_port_to_sock(port); sk = &tsk->sk; /* Queue message */ |
0c3141e91
|
1454 |
bh_lock_sock(sk); |
9816f0615
|
1455 |
|
0c3141e91
|
1456 |
if (!sock_owned_by_user(sk)) { |
e4de5fab8
|
1457 |
rc = filter_rcv(sk, buf); |
0c3141e91
|
1458 |
} else { |
4f4482dcd
|
1459 1460 1461 1462 |
if (sk->sk_backlog.len == 0) atomic_set(&tsk->dupl_rcvcnt, 0); limit = rcvbuf_limit(sk, buf) + atomic_read(&tsk->dupl_rcvcnt); if (sk_add_backlog(sk, buf, limit)) |
e4de5fab8
|
1463 |
rc = -TIPC_ERR_OVERLOAD; |
0c3141e91
|
1464 |
} |
9816f0615
|
1465 |
|
0c3141e91
|
1466 |
bh_unlock_sock(sk); |
9816f0615
|
1467 |
tipc_port_unlock(port); |
0c3141e91
|
1468 |
|
e4de5fab8
|
1469 |
if (likely(!rc)) |
9816f0615
|
1470 1471 |
return 0; exit: |
8db1bae30
|
1472 1473 1474 |
if (!tipc_msg_reverse(buf, &dnode, -rc)) return -EHOSTUNREACH; tipc_link_xmit2(buf, dnode, 0); |
9816f0615
|
1475 |
return -EHOSTUNREACH; |
b97bf3fd8
|
1476 |
} |
78eb3a537
|
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 |
static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) { struct sock *sk = sock->sk; DEFINE_WAIT(wait); int done; do { int err = sock_error(sk); if (err) return err; if (!*timeo_p) return -ETIMEDOUT; if (signal_pending(current)) return sock_intr_errno(*timeo_p); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); done = sk_wait_event(sk, timeo_p, sock->state != SS_CONNECTING); finish_wait(sk_sleep(sk), &wait); } while (!done); return 0; } |
b97bf3fd8
|
1498 |
/** |
247f0f3c3
|
1499 |
* tipc_connect - establish a connection to another TIPC port |
b97bf3fd8
|
1500 1501 1502 |
* @sock: socket structure * @dest: socket address for destination port * @destlen: size of socket address data structure |
0c3141e91
|
1503 |
* @flags: file-related flags associated with socket |
b97bf3fd8
|
1504 1505 1506 |
* * Returns 0 on success, errno otherwise */ |
247f0f3c3
|
1507 1508 |
static int tipc_connect(struct socket *sock, struct sockaddr *dest, int destlen, int flags) |
b97bf3fd8
|
1509 |
{ |
0c3141e91
|
1510 |
struct sock *sk = sock->sk; |
b89741a0c
|
1511 1512 |
struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; struct msghdr m = {NULL,}; |
78eb3a537
|
1513 1514 |
long timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; socket_state previous; |
b89741a0c
|
1515 |
int res; |
0c3141e91
|
1516 |
lock_sock(sk); |
b89741a0c
|
1517 |
/* For now, TIPC does not allow use of connect() with DGRAM/RDM types */ |
0c3141e91
|
1518 1519 1520 1521 |
if (sock->state == SS_READY) { res = -EOPNOTSUPP; goto exit; } |
b89741a0c
|
1522 |
|
b89741a0c
|
1523 1524 1525 1526 1527 1528 |
/* * Reject connection attempt using multicast address * * Note: send_msg() validates the rest of the address fields, * so there's no need to do it here */ |
0c3141e91
|
1529 1530 1531 1532 |
if (dst->addrtype == TIPC_ADDR_MCAST) { res = -EINVAL; goto exit; } |
78eb3a537
|
1533 |
previous = sock->state; |
584d24b39
|
1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 |
switch (sock->state) { case SS_UNCONNECTED: /* Send a 'SYN-' to destination */ m.msg_name = dest; m.msg_namelen = destlen; /* If connect is in non-blocking case, set MSG_DONTWAIT to * indicate send_msg() is never blocked. */ if (!timeout) m.msg_flags = MSG_DONTWAIT; |
247f0f3c3
|
1545 |
res = tipc_sendmsg(NULL, sock, &m, 0); |
584d24b39
|
1546 1547 1548 1549 1550 1551 1552 1553 |
if ((res < 0) && (res != -EWOULDBLOCK)) goto exit; /* Just entered SS_CONNECTING state; the only * difference is that return value in non-blocking * case is EINPROGRESS, rather than EALREADY. */ res = -EINPROGRESS; |
584d24b39
|
1554 |
case SS_CONNECTING: |
78eb3a537
|
1555 1556 1557 1558 1559 1560 1561 |
if (previous == SS_CONNECTING) res = -EALREADY; if (!timeout) goto exit; timeout = msecs_to_jiffies(timeout); /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ res = tipc_wait_for_connect(sock, &timeout); |
584d24b39
|
1562 1563 1564 1565 1566 1567 |
break; case SS_CONNECTED: res = -EISCONN; break; default: res = -EINVAL; |
78eb3a537
|
1568 |
break; |
b89741a0c
|
1569 |
} |
0c3141e91
|
1570 1571 |
exit: release_sock(sk); |
b89741a0c
|
1572 |
return res; |
b97bf3fd8
|
1573 |
} |
c43072852
|
1574 |
/** |
247f0f3c3
|
1575 |
* tipc_listen - allow socket to listen for incoming connections |
b97bf3fd8
|
1576 1577 |
* @sock: socket structure * @len: (unused) |
c43072852
|
1578 |
* |
b97bf3fd8
|
1579 1580 |
* Returns 0 on success, errno otherwise */ |
247f0f3c3
|
1581 |
static int tipc_listen(struct socket *sock, int len) |
b97bf3fd8
|
1582 |
{ |
0c3141e91
|
1583 1584 1585 1586 |
struct sock *sk = sock->sk; int res; lock_sock(sk); |
b97bf3fd8
|
1587 |
|
245f3d342
|
1588 |
if (sock->state != SS_UNCONNECTED) |
0c3141e91
|
1589 1590 1591 1592 1593 1594 1595 1596 |
res = -EINVAL; else { sock->state = SS_LISTENING; res = 0; } release_sock(sk); return res; |
b97bf3fd8
|
1597 |
} |
6398e23cd
|
1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 |
static int tipc_wait_for_accept(struct socket *sock, long timeo) { struct sock *sk = sock->sk; DEFINE_WAIT(wait); int err; /* True wake-one mechanism for incoming connections: only * one process gets woken up, not the 'whole herd'. * Since we do not 'race & poll' for established sockets * anymore, the common case will execute the loop only once. */ for (;;) { prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
fe8e46493
|
1612 |
if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { |
6398e23cd
|
1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 |
release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); } err = 0; if (!skb_queue_empty(&sk->sk_receive_queue)) break; err = -EINVAL; if (sock->state != SS_LISTENING) break; err = sock_intr_errno(timeo); if (signal_pending(current)) break; err = -EAGAIN; if (!timeo) break; } finish_wait(sk_sleep(sk), &wait); return err; } |
c43072852
|
1633 |
/** |
247f0f3c3
|
1634 |
* tipc_accept - wait for connection request |
b97bf3fd8
|
1635 1636 1637 |
* @sock: listening socket * @newsock: new socket that is to be connected * @flags: file-related flags associated with socket |
c43072852
|
1638 |
* |
b97bf3fd8
|
1639 1640 |
* Returns 0 on success, errno otherwise */ |
247f0f3c3
|
1641 |
static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) |
b97bf3fd8
|
1642 |
{ |
0fef8f205
|
1643 |
struct sock *new_sk, *sk = sock->sk; |
b97bf3fd8
|
1644 |
struct sk_buff *buf; |
8826cde65
|
1645 |
struct tipc_port *new_port; |
0fef8f205
|
1646 |
struct tipc_msg *msg; |
f9fef18c6
|
1647 |
struct tipc_portid peer; |
0fef8f205
|
1648 |
u32 new_ref; |
6398e23cd
|
1649 |
long timeo; |
0c3141e91
|
1650 |
int res; |
b97bf3fd8
|
1651 |
|
0c3141e91
|
1652 |
lock_sock(sk); |
b97bf3fd8
|
1653 |
|
0c3141e91
|
1654 1655 |
if (sock->state != SS_LISTENING) { res = -EINVAL; |
b97bf3fd8
|
1656 1657 |
goto exit; } |
6398e23cd
|
1658 1659 1660 1661 |
timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); res = tipc_wait_for_accept(sock, timeo); if (res) goto exit; |
0c3141e91
|
1662 1663 |
buf = skb_peek(&sk->sk_receive_queue); |
c5fa7b3cf
|
1664 |
res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, 1); |
0fef8f205
|
1665 1666 |
if (res) goto exit; |
b97bf3fd8
|
1667 |
|
0fef8f205
|
1668 |
new_sk = new_sock->sk; |
58ed94424
|
1669 |
new_port = &tipc_sk(new_sk)->port; |
8826cde65
|
1670 |
new_ref = new_port->ref; |
0fef8f205
|
1671 |
msg = buf_msg(buf); |
b97bf3fd8
|
1672 |
|
0fef8f205
|
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 |
/* we lock on new_sk; but lockdep sees the lock on sk */ lock_sock_nested(new_sk, SINGLE_DEPTH_NESTING); /* * Reject any stray messages received by new socket * before the socket lock was taken (very, very unlikely) */ reject_rx_queue(new_sk); /* Connect new socket to it's peer */ |
f9fef18c6
|
1683 1684 1685 |
peer.ref = msg_origport(msg); peer.node = msg_orignode(msg); tipc_port_connect(new_ref, &peer); |
0fef8f205
|
1686 |
new_sock->state = SS_CONNECTED; |
3b4f302d8
|
1687 |
tipc_port_set_importance(new_port, msg_importance(msg)); |
0fef8f205
|
1688 |
if (msg_named(msg)) { |
8826cde65
|
1689 1690 |
new_port->conn_type = msg_nametype(msg); new_port->conn_instance = msg_nameinst(msg); |
b97bf3fd8
|
1691 |
} |
0fef8f205
|
1692 1693 1694 1695 1696 1697 1698 1699 1700 |
/* * Respond to 'SYN-' by discarding it & returning 'ACK'-. * Respond to 'SYN+' by queuing it on new socket. */ if (!msg_data_sz(msg)) { struct msghdr m = {NULL,}; advance_rx_queue(sk); |
247f0f3c3
|
1701 |
tipc_send_packet(NULL, new_sock, &m, 0); |
0fef8f205
|
1702 1703 1704 |
} else { __skb_dequeue(&sk->sk_receive_queue); __skb_queue_head(&new_sk->sk_receive_queue, buf); |
aba79f332
|
1705 |
skb_set_owner_r(buf, new_sk); |
0fef8f205
|
1706 1707 |
} release_sock(new_sk); |
b97bf3fd8
|
1708 |
exit: |
0c3141e91
|
1709 |
release_sock(sk); |
b97bf3fd8
|
1710 1711 1712 1713 |
return res; } /** |
247f0f3c3
|
1714 |
* tipc_shutdown - shutdown socket connection |
b97bf3fd8
|
1715 |
* @sock: socket structure |
e247a8f5d
|
1716 |
* @how: direction to close (must be SHUT_RDWR) |
b97bf3fd8
|
1717 1718 |
* * Terminates connection (if necessary), then purges socket's receive queue. |
c43072852
|
1719 |
* |
b97bf3fd8
|
1720 1721 |
* Returns 0 on success, errno otherwise */ |
247f0f3c3
|
1722 |
static int tipc_shutdown(struct socket *sock, int how) |
b97bf3fd8
|
1723 |
{ |
0c3141e91
|
1724 |
struct sock *sk = sock->sk; |
58ed94424
|
1725 1726 |
struct tipc_sock *tsk = tipc_sk(sk); struct tipc_port *port = &tsk->port; |
b97bf3fd8
|
1727 |
struct sk_buff *buf; |
8db1bae30
|
1728 |
u32 peer; |
b97bf3fd8
|
1729 |
int res; |
e247a8f5d
|
1730 1731 |
if (how != SHUT_RDWR) return -EINVAL; |
b97bf3fd8
|
1732 |
|
0c3141e91
|
1733 |
lock_sock(sk); |
b97bf3fd8
|
1734 1735 |
switch (sock->state) { |
0c3141e91
|
1736 |
case SS_CONNECTING: |
b97bf3fd8
|
1737 |
case SS_CONNECTED: |
b97bf3fd8
|
1738 |
restart: |
617d3c7a5
|
1739 |
/* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ |
0c3141e91
|
1740 1741 |
buf = __skb_dequeue(&sk->sk_receive_queue); if (buf) { |
406824320
|
1742 |
if (TIPC_SKB_CB(buf)->handle != NULL) { |
5f6d9123f
|
1743 |
kfree_skb(buf); |
b97bf3fd8
|
1744 1745 |
goto restart; } |
58ed94424
|
1746 |
tipc_port_disconnect(port->ref); |
8db1bae30
|
1747 1748 |
if (tipc_msg_reverse(buf, &peer, TIPC_CONN_SHUTDOWN)) tipc_link_xmit2(buf, peer, 0); |
0c3141e91
|
1749 |
} else { |
58ed94424
|
1750 |
tipc_port_shutdown(port->ref); |
b97bf3fd8
|
1751 |
} |
0c3141e91
|
1752 1753 |
sock->state = SS_DISCONNECTING; |
b97bf3fd8
|
1754 1755 1756 1757 |
/* fall through */ case SS_DISCONNECTING: |
750311510
|
1758 |
/* Discard any unreceived messages */ |
57467e562
|
1759 |
__skb_queue_purge(&sk->sk_receive_queue); |
750311510
|
1760 1761 1762 |
/* Wake up anyone sleeping in poll */ sk->sk_state_change(sk); |
b97bf3fd8
|
1763 1764 1765 1766 1767 1768 |
res = 0; break; default: res = -ENOTCONN; } |
0c3141e91
|
1769 |
release_sock(sk); |
b97bf3fd8
|
1770 1771 1772 1773 |
return res; } /** |
247f0f3c3
|
1774 |
* tipc_setsockopt - set socket option |
b97bf3fd8
|
1775 1776 1777 1778 1779 |
* @sock: socket structure * @lvl: option level * @opt: option identifier * @ov: pointer to new option value * @ol: length of option value |
c43072852
|
1780 1781 |
* * For stream sockets only, accepts and ignores all IPPROTO_TCP options |
b97bf3fd8
|
1782 |
* (to ease compatibility). |
c43072852
|
1783 |
* |
b97bf3fd8
|
1784 1785 |
* Returns 0 on success, errno otherwise */ |
247f0f3c3
|
1786 1787 |
static int tipc_setsockopt(struct socket *sock, int lvl, int opt, char __user *ov, unsigned int ol) |
b97bf3fd8
|
1788 |
{ |
0c3141e91
|
1789 |
struct sock *sk = sock->sk; |
58ed94424
|
1790 1791 |
struct tipc_sock *tsk = tipc_sk(sk); struct tipc_port *port = &tsk->port; |
b97bf3fd8
|
1792 1793 |
u32 value; int res; |
c43072852
|
1794 1795 |
if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM)) return 0; |
b97bf3fd8
|
1796 1797 1798 1799 |
if (lvl != SOL_TIPC) return -ENOPROTOOPT; if (ol < sizeof(value)) return -EINVAL; |
2db9983a4
|
1800 1801 |
res = get_user(value, (u32 __user *)ov); if (res) |
b97bf3fd8
|
1802 |
return res; |
0c3141e91
|
1803 |
lock_sock(sk); |
c43072852
|
1804 |
|
b97bf3fd8
|
1805 1806 |
switch (opt) { case TIPC_IMPORTANCE: |
58ed94424
|
1807 |
tipc_port_set_importance(port, value); |
b97bf3fd8
|
1808 1809 1810 |
break; case TIPC_SRC_DROPPABLE: if (sock->type != SOCK_STREAM) |
58ed94424
|
1811 |
tipc_port_set_unreliable(port, value); |
c43072852
|
1812 |
else |
b97bf3fd8
|
1813 1814 1815 |
res = -ENOPROTOOPT; break; case TIPC_DEST_DROPPABLE: |
58ed94424
|
1816 |
tipc_port_set_unreturnable(port, value); |
b97bf3fd8
|
1817 1818 |
break; case TIPC_CONN_TIMEOUT: |
a0f40f02e
|
1819 |
tipc_sk(sk)->conn_timeout = value; |
0c3141e91
|
1820 |
/* no need to set "res", since already 0 at this point */ |
b97bf3fd8
|
1821 1822 1823 1824 |
break; default: res = -EINVAL; } |
0c3141e91
|
1825 |
release_sock(sk); |
b97bf3fd8
|
1826 1827 1828 1829 |
return res; } /** |
247f0f3c3
|
1830 |
* tipc_getsockopt - get socket option |
b97bf3fd8
|
1831 1832 1833 1834 1835 |
* @sock: socket structure * @lvl: option level * @opt: option identifier * @ov: receptacle for option value * @ol: receptacle for length of option value |
c43072852
|
1836 1837 |
* * For stream sockets only, returns 0 length result for all IPPROTO_TCP options |
b97bf3fd8
|
1838 |
* (to ease compatibility). |
c43072852
|
1839 |
* |
b97bf3fd8
|
1840 1841 |
* Returns 0 on success, errno otherwise */ |
247f0f3c3
|
1842 1843 |
static int tipc_getsockopt(struct socket *sock, int lvl, int opt, char __user *ov, int __user *ol) |
b97bf3fd8
|
1844 |
{ |
0c3141e91
|
1845 |
struct sock *sk = sock->sk; |
58ed94424
|
1846 1847 |
struct tipc_sock *tsk = tipc_sk(sk); struct tipc_port *port = &tsk->port; |
c43072852
|
1848 |
int len; |
b97bf3fd8
|
1849 |
u32 value; |
c43072852
|
1850 |
int res; |
b97bf3fd8
|
1851 |
|
c43072852
|
1852 1853 |
if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM)) return put_user(0, ol); |
b97bf3fd8
|
1854 1855 |
if (lvl != SOL_TIPC) return -ENOPROTOOPT; |
2db9983a4
|
1856 1857 |
res = get_user(len, ol); if (res) |
c43072852
|
1858 |
return res; |
b97bf3fd8
|
1859 |
|
0c3141e91
|
1860 |
lock_sock(sk); |
b97bf3fd8
|
1861 1862 1863 |
switch (opt) { case TIPC_IMPORTANCE: |
58ed94424
|
1864 |
value = tipc_port_importance(port); |
b97bf3fd8
|
1865 1866 |
break; case TIPC_SRC_DROPPABLE: |
58ed94424
|
1867 |
value = tipc_port_unreliable(port); |
b97bf3fd8
|
1868 1869 |
break; case TIPC_DEST_DROPPABLE: |
58ed94424
|
1870 |
value = tipc_port_unreturnable(port); |
b97bf3fd8
|
1871 1872 |
break; case TIPC_CONN_TIMEOUT: |
a0f40f02e
|
1873 |
value = tipc_sk(sk)->conn_timeout; |
0c3141e91
|
1874 |
/* no need to set "res", since already 0 at this point */ |
b97bf3fd8
|
1875 |
break; |
0e65967e3
|
1876 |
case TIPC_NODE_RECVQ_DEPTH: |
9da3d4758
|
1877 |
value = 0; /* was tipc_queue_size, now obsolete */ |
6650613d3
|
1878 |
break; |
0e65967e3
|
1879 |
case TIPC_SOCK_RECVQ_DEPTH: |
6650613d3
|
1880 1881 |
value = skb_queue_len(&sk->sk_receive_queue); break; |
b97bf3fd8
|
1882 1883 1884 |
default: res = -EINVAL; } |
0c3141e91
|
1885 |
release_sock(sk); |
25860c3bd
|
1886 1887 |
if (res) return res; /* "get" failed */ |
b97bf3fd8
|
1888 |
|
25860c3bd
|
1889 1890 1891 1892 1893 1894 1895 |
if (len < sizeof(value)) return -EINVAL; if (copy_to_user(ov, &value, sizeof(value))) return -EFAULT; return put_user(sizeof(value), ol); |
b97bf3fd8
|
1896 |
} |
78acb1f9b
|
1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 |
int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) { struct tipc_sioc_ln_req lnr; void __user *argp = (void __user *)arg; switch (cmd) { case SIOCGETLINKNAME: if (copy_from_user(&lnr, argp, sizeof(lnr))) return -EFAULT; if (!tipc_node_get_linkname(lnr.bearer_id, lnr.peer, lnr.linkname, TIPC_MAX_LINK_NAME)) { if (copy_to_user(argp, &lnr, sizeof(lnr))) return -EFAULT; return 0; } return -EADDRNOTAVAIL; break; default: return -ENOIOCTLCMD; } } |
ae86b9e38
|
1918 |
/* Protocol switches for the various types of TIPC sockets */ |
bca65eae3
|
1919 |
static const struct proto_ops msg_ops = { |
0e65967e3
|
1920 |
.owner = THIS_MODULE, |
b97bf3fd8
|
1921 |
.family = AF_TIPC, |
247f0f3c3
|
1922 1923 1924 |
.release = tipc_release, .bind = tipc_bind, .connect = tipc_connect, |
5eee6a6dc
|
1925 |
.socketpair = sock_no_socketpair, |
245f3d342
|
1926 |
.accept = sock_no_accept, |
247f0f3c3
|
1927 1928 |
.getname = tipc_getname, .poll = tipc_poll, |
78acb1f9b
|
1929 |
.ioctl = tipc_ioctl, |
245f3d342
|
1930 |
.listen = sock_no_listen, |
247f0f3c3
|
1931 1932 1933 1934 1935 |
.shutdown = tipc_shutdown, .setsockopt = tipc_setsockopt, .getsockopt = tipc_getsockopt, .sendmsg = tipc_sendmsg, .recvmsg = tipc_recvmsg, |
8238745a3
|
1936 1937 |
.mmap = sock_no_mmap, .sendpage = sock_no_sendpage |
b97bf3fd8
|
1938 |
}; |
bca65eae3
|
1939 |
static const struct proto_ops packet_ops = { |
0e65967e3
|
1940 |
.owner = THIS_MODULE, |
b97bf3fd8
|
1941 |
.family = AF_TIPC, |
247f0f3c3
|
1942 1943 1944 |
.release = tipc_release, .bind = tipc_bind, .connect = tipc_connect, |
5eee6a6dc
|
1945 |
.socketpair = sock_no_socketpair, |
247f0f3c3
|
1946 1947 1948 |
.accept = tipc_accept, .getname = tipc_getname, .poll = tipc_poll, |
78acb1f9b
|
1949 |
.ioctl = tipc_ioctl, |
247f0f3c3
|
1950 1951 1952 1953 1954 1955 |
.listen = tipc_listen, .shutdown = tipc_shutdown, .setsockopt = tipc_setsockopt, .getsockopt = tipc_getsockopt, .sendmsg = tipc_send_packet, .recvmsg = tipc_recvmsg, |
8238745a3
|
1956 1957 |
.mmap = sock_no_mmap, .sendpage = sock_no_sendpage |
b97bf3fd8
|
1958 |
}; |
bca65eae3
|
1959 |
static const struct proto_ops stream_ops = { |
0e65967e3
|
1960 |
.owner = THIS_MODULE, |
b97bf3fd8
|
1961 |
.family = AF_TIPC, |
247f0f3c3
|
1962 1963 1964 |
.release = tipc_release, .bind = tipc_bind, .connect = tipc_connect, |
5eee6a6dc
|
1965 |
.socketpair = sock_no_socketpair, |
247f0f3c3
|
1966 1967 1968 |
.accept = tipc_accept, .getname = tipc_getname, .poll = tipc_poll, |
78acb1f9b
|
1969 |
.ioctl = tipc_ioctl, |
247f0f3c3
|
1970 1971 1972 1973 1974 1975 |
.listen = tipc_listen, .shutdown = tipc_shutdown, .setsockopt = tipc_setsockopt, .getsockopt = tipc_getsockopt, .sendmsg = tipc_send_stream, .recvmsg = tipc_recv_stream, |
8238745a3
|
1976 1977 |
.mmap = sock_no_mmap, .sendpage = sock_no_sendpage |
b97bf3fd8
|
1978 |
}; |
bca65eae3
|
1979 |
static const struct net_proto_family tipc_family_ops = { |
0e65967e3
|
1980 |
.owner = THIS_MODULE, |
b97bf3fd8
|
1981 |
.family = AF_TIPC, |
c5fa7b3cf
|
1982 |
.create = tipc_sk_create |
b97bf3fd8
|
1983 1984 1985 1986 1987 |
}; static struct proto tipc_proto = { .name = "TIPC", .owner = THIS_MODULE, |
cc79dd1ba
|
1988 1989 |
.obj_size = sizeof(struct tipc_sock), .sysctl_rmem = sysctl_tipc_rmem |
b97bf3fd8
|
1990 |
}; |
c5fa7b3cf
|
1991 1992 1993 1994 1995 |
static struct proto tipc_proto_kern = { .name = "TIPC", .obj_size = sizeof(struct tipc_sock), .sysctl_rmem = sysctl_tipc_rmem }; |
b97bf3fd8
|
1996 |
/** |
4323add67
|
1997 |
* tipc_socket_init - initialize TIPC socket interface |
c43072852
|
1998 |
* |
b97bf3fd8
|
1999 2000 |
* Returns 0 on success, errno otherwise */ |
4323add67
|
2001 |
int tipc_socket_init(void) |
b97bf3fd8
|
2002 2003 |
{ int res; |
c43072852
|
2004 |
res = proto_register(&tipc_proto, 1); |
b97bf3fd8
|
2005 |
if (res) { |
2cf8aa19f
|
2006 2007 |
pr_err("Failed to register TIPC protocol type "); |
b97bf3fd8
|
2008 2009 2010 2011 2012 |
goto out; } res = sock_register(&tipc_family_ops); if (res) { |
2cf8aa19f
|
2013 2014 |
pr_err("Failed to register TIPC socket type "); |
b97bf3fd8
|
2015 2016 2017 |
proto_unregister(&tipc_proto); goto out; } |
b97bf3fd8
|
2018 2019 2020 2021 2022 |
out: return res; } /** |
4323add67
|
2023 |
* tipc_socket_stop - stop TIPC socket interface |
b97bf3fd8
|
2024 |
*/ |
4323add67
|
2025 |
void tipc_socket_stop(void) |
b97bf3fd8
|
2026 |
{ |
b97bf3fd8
|
2027 2028 2029 |
sock_unregister(tipc_family_ops.family); proto_unregister(&tipc_proto); } |