diff options
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r-- | net/tipc/socket.c | 1722 |
1 files changed, 1722 insertions, 0 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c new file mode 100644 index 000000000000..22dcb724e760 --- /dev/null +++ b/net/tipc/socket.c | |||
@@ -0,0 +1,1722 @@ | |||
1 | /* | ||
2 | * net/tipc/socket.c: TIPC socket API | ||
3 | * | ||
4 | * Copyright (c) 2003-2005, Ericsson Research Canada | ||
5 | * Copyright (c) 2004-2005, Wind River Systems | ||
6 | * Copyright (c) 2005-2006, Ericsson AB | ||
7 | * All rights reserved. | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions are met: | ||
11 | * | ||
12 | * Redistributions of source code must retain the above copyright notice, this | ||
13 | * list of conditions and the following disclaimer. | ||
14 | * Redistributions in binary form must reproduce the above copyright notice, | ||
15 | * this list of conditions and the following disclaimer in the documentation | ||
16 | * and/or other materials provided with the distribution. | ||
17 | * Neither the names of the copyright holders nor the names of its | ||
18 | * contributors may be used to endorse or promote products derived from this | ||
19 | * software without specific prior written permission. | ||
20 | * | ||
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
31 | * POSSIBILITY OF SUCH DAMAGE. | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/net.h> | ||
37 | #include <linux/socket.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/mm.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/poll.h> | ||
42 | #include <linux/version.h> | ||
43 | #include <linux/fcntl.h> | ||
44 | #include <linux/version.h> | ||
45 | #include <asm/semaphore.h> | ||
46 | #include <asm/string.h> | ||
47 | #include <asm/atomic.h> | ||
48 | #include <net/sock.h> | ||
49 | |||
50 | #include <linux/tipc.h> | ||
51 | #include <net/tipc/tipc_msg.h> | ||
52 | #include <net/tipc/tipc_port.h> | ||
53 | |||
54 | #include "core.h" | ||
55 | |||
56 | #define SS_LISTENING -1 /* socket is listening */ | ||
57 | #define SS_READY -2 /* socket is connectionless */ | ||
58 | |||
59 | #define OVERLOAD_LIMIT_BASE 5000 | ||
60 | |||
61 | struct tipc_sock { | ||
62 | struct sock sk; | ||
63 | struct tipc_port *p; | ||
64 | struct semaphore sem; | ||
65 | }; | ||
66 | |||
67 | #define tipc_sk(sk) ((struct tipc_sock*)sk) | ||
68 | |||
69 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); | ||
70 | static void wakeupdispatch(struct tipc_port *tport); | ||
71 | |||
72 | static struct proto_ops packet_ops; | ||
73 | static struct proto_ops stream_ops; | ||
74 | static struct proto_ops msg_ops; | ||
75 | |||
76 | static struct proto tipc_proto; | ||
77 | |||
78 | static int sockets_enabled = 0; | ||
79 | |||
80 | static atomic_t tipc_queue_size = ATOMIC_INIT(0); | ||
81 | |||
82 | |||
83 | /* | ||
84 | * sock_lock(): Lock a port/socket pair. lock_sock() can | ||
85 | * not be used here, since the same lock must protect ports | ||
86 | * with non-socket interfaces. | ||
87 | * See net.c for description of locking policy. | ||
88 | */ | ||
89 | static inline void sock_lock(struct tipc_sock* tsock) | ||
90 | { | ||
91 | spin_lock_bh(tsock->p->lock); | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * sock_unlock(): Unlock a port/socket pair | ||
96 | */ | ||
97 | static inline void sock_unlock(struct tipc_sock* tsock) | ||
98 | { | ||
99 | spin_unlock_bh(tsock->p->lock); | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * pollmask - determine the current set of poll() events for a socket | ||
104 | * @sock: socket structure | ||
105 | * | ||
106 | * TIPC sets the returned events as follows: | ||
107 | * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty | ||
108 | * or if a connection-oriented socket is does not have an active connection | ||
109 | * (i.e. a read operation will not block). | ||
110 | * b) POLLOUT is set except when a socket's connection has been terminated | ||
111 | * (i.e. a write operation will not block). | ||
112 | * c) POLLHUP is set when a socket's connection has been terminated. | ||
113 | * | ||
114 | * IMPORTANT: The fact that a read or write operation will not block does NOT | ||
115 | * imply that the operation will succeed! | ||
116 | * | ||
117 | * Returns pollmask value | ||
118 | */ | ||
119 | |||
120 | static inline u32 pollmask(struct socket *sock) | ||
121 | { | ||
122 | u32 mask; | ||
123 | |||
124 | if ((skb_queue_len(&sock->sk->sk_receive_queue) != 0) || | ||
125 | (sock->state == SS_UNCONNECTED) || | ||
126 | (sock->state == SS_DISCONNECTING)) | ||
127 | mask = (POLLRDNORM | POLLIN); | ||
128 | else | ||
129 | mask = 0; | ||
130 | |||
131 | if (sock->state == SS_DISCONNECTING) | ||
132 | mask |= POLLHUP; | ||
133 | else | ||
134 | mask |= POLLOUT; | ||
135 | |||
136 | return mask; | ||
137 | } | ||
138 | |||
139 | |||
140 | /** | ||
141 | * advance_queue - discard first buffer in queue | ||
142 | * @tsock: TIPC socket | ||
143 | */ | ||
144 | |||
145 | static inline void advance_queue(struct tipc_sock *tsock) | ||
146 | { | ||
147 | sock_lock(tsock); | ||
148 | buf_discard(skb_dequeue(&tsock->sk.sk_receive_queue)); | ||
149 | sock_unlock(tsock); | ||
150 | atomic_dec(&tipc_queue_size); | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * tipc_create - create a TIPC socket | ||
155 | * @sock: pre-allocated socket structure | ||
156 | * @protocol: protocol indicator (must be 0) | ||
157 | * | ||
158 | * This routine creates and attaches a 'struct sock' to the 'struct socket', | ||
159 | * then create and attaches a TIPC port to the 'struct sock' part. | ||
160 | * | ||
161 | * Returns 0 on success, errno otherwise | ||
162 | */ | ||
163 | static int tipc_create(struct socket *sock, int protocol) | ||
164 | { | ||
165 | struct tipc_sock *tsock; | ||
166 | struct tipc_port *port; | ||
167 | struct sock *sk; | ||
168 | u32 ref; | ||
169 | |||
170 | if ((sock->type != SOCK_STREAM) && | ||
171 | (sock->type != SOCK_SEQPACKET) && | ||
172 | (sock->type != SOCK_DGRAM) && | ||
173 | (sock->type != SOCK_RDM)) | ||
174 | return -EPROTOTYPE; | ||
175 | |||
176 | if (unlikely(protocol != 0)) | ||
177 | return -EPROTONOSUPPORT; | ||
178 | |||
179 | ref = tipc_createport_raw(0, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE); | ||
180 | if (unlikely(!ref)) | ||
181 | return -ENOMEM; | ||
182 | |||
183 | sock->state = SS_UNCONNECTED; | ||
184 | |||
185 | switch (sock->type) { | ||
186 | case SOCK_STREAM: | ||
187 | sock->ops = &stream_ops; | ||
188 | break; | ||
189 | case SOCK_SEQPACKET: | ||
190 | sock->ops = &packet_ops; | ||
191 | break; | ||
192 | case SOCK_DGRAM: | ||
193 | tipc_set_portunreliable(ref, 1); | ||
194 | /* fall through */ | ||
195 | case SOCK_RDM: | ||
196 | tipc_set_portunreturnable(ref, 1); | ||
197 | sock->ops = &msg_ops; | ||
198 | sock->state = SS_READY; | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1); | ||
203 | if (!sk) { | ||
204 | tipc_deleteport(ref); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | |||
208 | sock_init_data(sock, sk); | ||
209 | init_waitqueue_head(sk->sk_sleep); | ||
210 | sk->sk_rcvtimeo = 8 * HZ; /* default connect timeout = 8s */ | ||
211 | |||
212 | tsock = tipc_sk(sk); | ||
213 | port = tipc_get_port(ref); | ||
214 | |||
215 | tsock->p = port; | ||
216 | port->usr_handle = tsock; | ||
217 | |||
218 | init_MUTEX(&tsock->sem); | ||
219 | |||
220 | dbg("sock_create: %x\n",tsock); | ||
221 | |||
222 | atomic_inc(&tipc_user_count); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * release - destroy a TIPC socket | ||
229 | * @sock: socket to destroy | ||
230 | * | ||
231 | * This routine cleans up any messages that are still queued on the socket. | ||
232 | * For DGRAM and RDM socket types, all queued messages are rejected. | ||
233 | * For SEQPACKET and STREAM socket types, the first message is rejected | ||
234 | * and any others are discarded. (If the first message on a STREAM socket | ||
235 | * is partially-read, it is discarded and the next one is rejected instead.) | ||
236 | * | ||
237 | * NOTE: Rejected messages are not necessarily returned to the sender! They | ||
238 | * are returned or discarded according to the "destination droppable" setting | ||
239 | * specified for the message by the sender. | ||
240 | * | ||
241 | * Returns 0 on success, errno otherwise | ||
242 | */ | ||
243 | |||
244 | static int release(struct socket *sock) | ||
245 | { | ||
246 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
247 | struct sock *sk = sock->sk; | ||
248 | int res = TIPC_OK; | ||
249 | struct sk_buff *buf; | ||
250 | |||
251 | dbg("sock_delete: %x\n",tsock); | ||
252 | if (!tsock) | ||
253 | return 0; | ||
254 | down_interruptible(&tsock->sem); | ||
255 | if (!sock->sk) { | ||
256 | up(&tsock->sem); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* Reject unreceived messages, unless no longer connected */ | ||
261 | |||
262 | while (sock->state != SS_DISCONNECTING) { | ||
263 | sock_lock(tsock); | ||
264 | buf = skb_dequeue(&sk->sk_receive_queue); | ||
265 | if (!buf) | ||
266 | tsock->p->usr_handle = 0; | ||
267 | sock_unlock(tsock); | ||
268 | if (!buf) | ||
269 | break; | ||
270 | if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) | ||
271 | buf_discard(buf); | ||
272 | else | ||
273 | tipc_reject_msg(buf, TIPC_ERR_NO_PORT); | ||
274 | atomic_dec(&tipc_queue_size); | ||
275 | } | ||
276 | |||
277 | /* Delete TIPC port */ | ||
278 | |||
279 | res = tipc_deleteport(tsock->p->ref); | ||
280 | sock->sk = NULL; | ||
281 | |||
282 | /* Discard any remaining messages */ | ||
283 | |||
284 | while ((buf = skb_dequeue(&sk->sk_receive_queue))) { | ||
285 | buf_discard(buf); | ||
286 | atomic_dec(&tipc_queue_size); | ||
287 | } | ||
288 | |||
289 | up(&tsock->sem); | ||
290 | |||
291 | sock_put(sk); | ||
292 | |||
293 | atomic_dec(&tipc_user_count); | ||
294 | return res; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * bind - associate or disassocate TIPC name(s) with a socket | ||
299 | * @sock: socket structure | ||
300 | * @uaddr: socket address describing name(s) and desired operation | ||
301 | * @uaddr_len: size of socket address data structure | ||
302 | * | ||
303 | * Name and name sequence binding is indicated using a positive scope value; | ||
304 | * a negative scope value unbinds the specified name. Specifying no name | ||
305 | * (i.e. a socket address length of 0) unbinds all names from the socket. | ||
306 | * | ||
307 | * Returns 0 on success, errno otherwise | ||
308 | */ | ||
309 | |||
310 | static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) | ||
311 | { | ||
312 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
313 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; | ||
314 | int res; | ||
315 | |||
316 | if (down_interruptible(&tsock->sem)) | ||
317 | return -ERESTARTSYS; | ||
318 | |||
319 | if (unlikely(!uaddr_len)) { | ||
320 | res = tipc_withdraw(tsock->p->ref, 0, 0); | ||
321 | goto exit; | ||
322 | } | ||
323 | |||
324 | if (uaddr_len < sizeof(struct sockaddr_tipc)) { | ||
325 | res = -EINVAL; | ||
326 | goto exit; | ||
327 | } | ||
328 | |||
329 | if (addr->family != AF_TIPC) { | ||
330 | res = -EAFNOSUPPORT; | ||
331 | goto exit; | ||
332 | } | ||
333 | if (addr->addrtype == TIPC_ADDR_NAME) | ||
334 | addr->addr.nameseq.upper = addr->addr.nameseq.lower; | ||
335 | else if (addr->addrtype != TIPC_ADDR_NAMESEQ) { | ||
336 | res = -EAFNOSUPPORT; | ||
337 | goto exit; | ||
338 | } | ||
339 | |||
340 | if (addr->scope > 0) | ||
341 | res = tipc_publish(tsock->p->ref, addr->scope, | ||
342 | &addr->addr.nameseq); | ||
343 | else | ||
344 | res = tipc_withdraw(tsock->p->ref, -addr->scope, | ||
345 | &addr->addr.nameseq); | ||
346 | exit: | ||
347 | up(&tsock->sem); | ||
348 | return res; | ||
349 | } | ||
350 | |||
351 | /** | ||
352 | * get_name - get port ID of socket or peer socket | ||
353 | * @sock: socket structure | ||
354 | * @uaddr: area for returned socket address | ||
355 | * @uaddr_len: area for returned length of socket address | ||
356 | * @peer: 0 to obtain socket name, 1 to obtain peer socket name | ||
357 | * | ||
358 | * Returns 0 on success, errno otherwise | ||
359 | */ | ||
360 | |||
361 | static int get_name(struct socket *sock, struct sockaddr *uaddr, | ||
362 | int *uaddr_len, int peer) | ||
363 | { | ||
364 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
365 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; | ||
366 | u32 res; | ||
367 | |||
368 | if (down_interruptible(&tsock->sem)) | ||
369 | return -ERESTARTSYS; | ||
370 | |||
371 | *uaddr_len = sizeof(*addr); | ||
372 | addr->addrtype = TIPC_ADDR_ID; | ||
373 | addr->family = AF_TIPC; | ||
374 | addr->scope = 0; | ||
375 | if (peer) | ||
376 | res = tipc_peer(tsock->p->ref, &addr->addr.id); | ||
377 | else | ||
378 | res = tipc_ownidentity(tsock->p->ref, &addr->addr.id); | ||
379 | addr->addr.name.domain = 0; | ||
380 | |||
381 | up(&tsock->sem); | ||
382 | return res; | ||
383 | } | ||
384 | |||
385 | /** | ||
386 | * poll - read and possibly block on pollmask | ||
387 | * @file: file structure associated with the socket | ||
388 | * @sock: socket for which to calculate the poll bits | ||
389 | * @wait: ??? | ||
390 | * | ||
391 | * Returns the pollmask | ||
392 | */ | ||
393 | |||
394 | static unsigned int poll(struct file *file, struct socket *sock, | ||
395 | poll_table *wait) | ||
396 | { | ||
397 | poll_wait(file, sock->sk->sk_sleep, wait); | ||
398 | /* NEED LOCK HERE? */ | ||
399 | return pollmask(sock); | ||
400 | } | ||
401 | |||
402 | /** | ||
403 | * dest_name_check - verify user is permitted to send to specified port name | ||
404 | * @dest: destination address | ||
405 | * @m: descriptor for message to be sent | ||
406 | * | ||
407 | * Prevents restricted configuration commands from being issued by | ||
408 | * unauthorized users. | ||
409 | * | ||
410 | * Returns 0 if permission is granted, otherwise errno | ||
411 | */ | ||
412 | |||
413 | static inline int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) | ||
414 | { | ||
415 | struct tipc_cfg_msg_hdr hdr; | ||
416 | |||
417 | if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES)) | ||
418 | return 0; | ||
419 | if (likely(dest->addr.name.name.type == TIPC_TOP_SRV)) | ||
420 | return 0; | ||
421 | |||
422 | if (likely(dest->addr.name.name.type != TIPC_CFG_SRV)) | ||
423 | return -EACCES; | ||
424 | |||
425 | if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr))) | ||
426 | return -EFAULT; | ||
427 | if ((ntohs(hdr.tcm_type) & 0xC000) & (!capable(CAP_NET_ADMIN))) | ||
428 | return -EACCES; | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | /** | ||
434 | * send_msg - send message in connectionless manner | ||
435 | * @iocb: (unused) | ||
436 | * @sock: socket structure | ||
437 | * @m: message to send | ||
438 | * @total_len: (unused) | ||
439 | * | ||
440 | * Message must have an destination specified explicitly. | ||
441 | * Used for SOCK_RDM and SOCK_DGRAM messages, | ||
442 | * and for 'SYN' messages on SOCK_SEQPACKET and SOCK_STREAM connections. | ||
443 | * (Note: 'SYN+' is prohibited on SOCK_STREAM.) | ||
444 | * | ||
445 | * Returns the number of bytes sent on success, or errno otherwise | ||
446 | */ | ||
447 | |||
448 | static int send_msg(struct kiocb *iocb, struct socket *sock, | ||
449 | struct msghdr *m, size_t total_len) | ||
450 | { | ||
451 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
452 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | ||
453 | struct sk_buff *buf; | ||
454 | int needs_conn; | ||
455 | int res = -EINVAL; | ||
456 | |||
457 | if (unlikely(!dest)) | ||
458 | return -EDESTADDRREQ; | ||
459 | if (unlikely(dest->family != AF_TIPC)) | ||
460 | return -EINVAL; | ||
461 | |||
462 | needs_conn = (sock->state != SS_READY); | ||
463 | if (unlikely(needs_conn)) { | ||
464 | if (sock->state == SS_LISTENING) | ||
465 | return -EPIPE; | ||
466 | if (sock->state != SS_UNCONNECTED) | ||
467 | return -EISCONN; | ||
468 | if ((tsock->p->published) || | ||
469 | ((sock->type == SOCK_STREAM) && (total_len != 0))) | ||
470 | return -EOPNOTSUPP; | ||
471 | } | ||
472 | |||
473 | if (down_interruptible(&tsock->sem)) | ||
474 | return -ERESTARTSYS; | ||
475 | |||
476 | if (needs_conn) { | ||
477 | |||
478 | /* Abort any pending connection attempts (very unlikely) */ | ||
479 | |||
480 | while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) { | ||
481 | tipc_reject_msg(buf, TIPC_ERR_NO_PORT); | ||
482 | atomic_dec(&tipc_queue_size); | ||
483 | } | ||
484 | |||
485 | sock->state = SS_CONNECTING; | ||
486 | } | ||
487 | |||
488 | do { | ||
489 | if (dest->addrtype == TIPC_ADDR_NAME) { | ||
490 | if ((res = dest_name_check(dest, m))) | ||
491 | goto exit; | ||
492 | res = tipc_send2name(tsock->p->ref, | ||
493 | &dest->addr.name.name, | ||
494 | dest->addr.name.domain, | ||
495 | m->msg_iovlen, | ||
496 | m->msg_iov); | ||
497 | } | ||
498 | else if (dest->addrtype == TIPC_ADDR_ID) { | ||
499 | res = tipc_send2port(tsock->p->ref, | ||
500 | &dest->addr.id, | ||
501 | m->msg_iovlen, | ||
502 | m->msg_iov); | ||
503 | } | ||
504 | else if (dest->addrtype == TIPC_ADDR_MCAST) { | ||
505 | if (needs_conn) { | ||
506 | res = -EOPNOTSUPP; | ||
507 | goto exit; | ||
508 | } | ||
509 | if ((res = dest_name_check(dest, m))) | ||
510 | goto exit; | ||
511 | res = tipc_multicast(tsock->p->ref, | ||
512 | &dest->addr.nameseq, | ||
513 | 0, | ||
514 | m->msg_iovlen, | ||
515 | m->msg_iov); | ||
516 | } | ||
517 | if (likely(res != -ELINKCONG)) { | ||
518 | exit: | ||
519 | up(&tsock->sem); | ||
520 | return res; | ||
521 | } | ||
522 | if (m->msg_flags & MSG_DONTWAIT) { | ||
523 | res = -EWOULDBLOCK; | ||
524 | goto exit; | ||
525 | } | ||
526 | if (wait_event_interruptible(*sock->sk->sk_sleep, | ||
527 | !tsock->p->congested)) { | ||
528 | res = -ERESTARTSYS; | ||
529 | goto exit; | ||
530 | } | ||
531 | } while (1); | ||
532 | } | ||
533 | |||
534 | /** | ||
535 | * send_packet - send a connection-oriented message | ||
536 | * @iocb: (unused) | ||
537 | * @sock: socket structure | ||
538 | * @m: message to send | ||
539 | * @total_len: (unused) | ||
540 | * | ||
541 | * Used for SOCK_SEQPACKET messages and SOCK_STREAM data. | ||
542 | * | ||
543 | * Returns the number of bytes sent on success, or errno otherwise | ||
544 | */ | ||
545 | |||
546 | static int send_packet(struct kiocb *iocb, struct socket *sock, | ||
547 | struct msghdr *m, size_t total_len) | ||
548 | { | ||
549 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
550 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | ||
551 | int res; | ||
552 | |||
553 | /* Handle implied connection establishment */ | ||
554 | |||
555 | if (unlikely(dest)) | ||
556 | return send_msg(iocb, sock, m, total_len); | ||
557 | |||
558 | if (down_interruptible(&tsock->sem)) { | ||
559 | return -ERESTARTSYS; | ||
560 | } | ||
561 | |||
562 | if (unlikely(sock->state != SS_CONNECTED)) { | ||
563 | if (sock->state == SS_DISCONNECTING) | ||
564 | res = -EPIPE; | ||
565 | else | ||
566 | res = -ENOTCONN; | ||
567 | goto exit; | ||
568 | } | ||
569 | |||
570 | do { | ||
571 | res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov); | ||
572 | if (likely(res != -ELINKCONG)) { | ||
573 | exit: | ||
574 | up(&tsock->sem); | ||
575 | return res; | ||
576 | } | ||
577 | if (m->msg_flags & MSG_DONTWAIT) { | ||
578 | res = -EWOULDBLOCK; | ||
579 | goto exit; | ||
580 | } | ||
581 | if (wait_event_interruptible(*sock->sk->sk_sleep, | ||
582 | !tsock->p->congested)) { | ||
583 | res = -ERESTARTSYS; | ||
584 | goto exit; | ||
585 | } | ||
586 | } while (1); | ||
587 | } | ||
588 | |||
589 | /** | ||
590 | * send_stream - send stream-oriented data | ||
591 | * @iocb: (unused) | ||
592 | * @sock: socket structure | ||
593 | * @m: data to send | ||
594 | * @total_len: total length of data to be sent | ||
595 | * | ||
596 | * Used for SOCK_STREAM data. | ||
597 | * | ||
598 | * Returns the number of bytes sent on success, or errno otherwise | ||
599 | */ | ||
600 | |||
601 | |||
602 | static int send_stream(struct kiocb *iocb, struct socket *sock, | ||
603 | struct msghdr *m, size_t total_len) | ||
604 | { | ||
605 | struct msghdr my_msg; | ||
606 | struct iovec my_iov; | ||
607 | struct iovec *curr_iov; | ||
608 | int curr_iovlen; | ||
609 | char __user *curr_start; | ||
610 | int curr_left; | ||
611 | int bytes_to_send; | ||
612 | int res; | ||
613 | |||
614 | if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE)) | ||
615 | return send_packet(iocb, sock, m, total_len); | ||
616 | |||
617 | /* Can only send large data streams if already connected */ | ||
618 | |||
619 | if (unlikely(sock->state != SS_CONNECTED)) { | ||
620 | if (sock->state == SS_DISCONNECTING) | ||
621 | return -EPIPE; | ||
622 | else | ||
623 | return -ENOTCONN; | ||
624 | } | ||
625 | |||
626 | /* | ||
627 | * Send each iovec entry using one or more messages | ||
628 | * | ||
629 | * Note: This algorithm is good for the most likely case | ||
630 | * (i.e. one large iovec entry), but could be improved to pass sets | ||
631 | * of small iovec entries into send_packet(). | ||
632 | */ | ||
633 | |||
634 | my_msg = *m; | ||
635 | curr_iov = my_msg.msg_iov; | ||
636 | curr_iovlen = my_msg.msg_iovlen; | ||
637 | my_msg.msg_iov = &my_iov; | ||
638 | my_msg.msg_iovlen = 1; | ||
639 | |||
640 | while (curr_iovlen--) { | ||
641 | curr_start = curr_iov->iov_base; | ||
642 | curr_left = curr_iov->iov_len; | ||
643 | |||
644 | while (curr_left) { | ||
645 | bytes_to_send = (curr_left < TIPC_MAX_USER_MSG_SIZE) | ||
646 | ? curr_left : TIPC_MAX_USER_MSG_SIZE; | ||
647 | my_iov.iov_base = curr_start; | ||
648 | my_iov.iov_len = bytes_to_send; | ||
649 | if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0) | ||
650 | return res; | ||
651 | curr_left -= bytes_to_send; | ||
652 | curr_start += bytes_to_send; | ||
653 | } | ||
654 | |||
655 | curr_iov++; | ||
656 | } | ||
657 | |||
658 | return total_len; | ||
659 | } | ||
660 | |||
661 | /** | ||
662 | * auto_connect - complete connection setup to a remote port | ||
663 | * @sock: socket structure | ||
664 | * @tsock: TIPC-specific socket structure | ||
665 | * @msg: peer's response message | ||
666 | * | ||
667 | * Returns 0 on success, errno otherwise | ||
668 | */ | ||
669 | |||
670 | static int auto_connect(struct socket *sock, struct tipc_sock *tsock, | ||
671 | struct tipc_msg *msg) | ||
672 | { | ||
673 | struct tipc_portid peer; | ||
674 | |||
675 | if (msg_errcode(msg)) { | ||
676 | sock->state = SS_DISCONNECTING; | ||
677 | return -ECONNREFUSED; | ||
678 | } | ||
679 | |||
680 | peer.ref = msg_origport(msg); | ||
681 | peer.node = msg_orignode(msg); | ||
682 | tipc_connect2port(tsock->p->ref, &peer); | ||
683 | tipc_set_portimportance(tsock->p->ref, msg_importance(msg)); | ||
684 | sock->state = SS_CONNECTED; | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | /** | ||
689 | * set_orig_addr - capture sender's address for received message | ||
690 | * @m: descriptor for message info | ||
691 | * @msg: received message header | ||
692 | * | ||
693 | * Note: Address is not captured if not requested by receiver. | ||
694 | */ | ||
695 | |||
696 | static inline void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) | ||
697 | { | ||
698 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name; | ||
699 | |||
700 | if (addr) { | ||
701 | addr->family = AF_TIPC; | ||
702 | addr->addrtype = TIPC_ADDR_ID; | ||
703 | addr->addr.id.ref = msg_origport(msg); | ||
704 | addr->addr.id.node = msg_orignode(msg); | ||
705 | addr->addr.name.domain = 0; /* could leave uninitialized */ | ||
706 | addr->scope = 0; /* could leave uninitialized */ | ||
707 | m->msg_namelen = sizeof(struct sockaddr_tipc); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | /** | ||
712 | * anc_data_recv - optionally capture ancillary data for received message | ||
713 | * @m: descriptor for message info | ||
714 | * @msg: received message header | ||
715 | * @tport: TIPC port associated with message | ||
716 | * | ||
717 | * Note: Ancillary data is not captured if not requested by receiver. | ||
718 | * | ||
719 | * Returns 0 if successful, otherwise errno | ||
720 | */ | ||
721 | |||
722 | static inline int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, | ||
723 | struct tipc_port *tport) | ||
724 | { | ||
725 | u32 anc_data[3]; | ||
726 | u32 err; | ||
727 | u32 dest_type; | ||
728 | int res; | ||
729 | |||
730 | if (likely(m->msg_controllen == 0)) | ||
731 | return 0; | ||
732 | |||
733 | /* Optionally capture errored message object(s) */ | ||
734 | |||
735 | err = msg ? msg_errcode(msg) : 0; | ||
736 | if (unlikely(err)) { | ||
737 | anc_data[0] = err; | ||
738 | anc_data[1] = msg_data_sz(msg); | ||
739 | if ((res = put_cmsg(m, SOL_SOCKET, TIPC_ERRINFO, 8, anc_data))) | ||
740 | return res; | ||
741 | if (anc_data[1] && | ||
742 | (res = put_cmsg(m, SOL_SOCKET, TIPC_RETDATA, anc_data[1], | ||
743 | msg_data(msg)))) | ||
744 | return res; | ||
745 | } | ||
746 | |||
747 | /* Optionally capture message destination object */ | ||
748 | |||
749 | dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG; | ||
750 | switch (dest_type) { | ||
751 | case TIPC_NAMED_MSG: | ||
752 | anc_data[0] = msg_nametype(msg); | ||
753 | anc_data[1] = msg_namelower(msg); | ||
754 | anc_data[2] = msg_namelower(msg); | ||
755 | break; | ||
756 | case TIPC_MCAST_MSG: | ||
757 | anc_data[0] = msg_nametype(msg); | ||
758 | anc_data[1] = msg_namelower(msg); | ||
759 | anc_data[2] = msg_nameupper(msg); | ||
760 | break; | ||
761 | case TIPC_CONN_MSG: | ||
762 | anc_data[0] = tport->conn_type; | ||
763 | anc_data[1] = tport->conn_instance; | ||
764 | anc_data[2] = tport->conn_instance; | ||
765 | break; | ||
766 | default: | ||
767 | anc_data[0] = 0; | ||
768 | } | ||
769 | if (anc_data[0] && | ||
770 | (res = put_cmsg(m, SOL_SOCKET, TIPC_DESTNAME, 12, anc_data))) | ||
771 | return res; | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | /** | ||
777 | * recv_msg - receive packet-oriented message | ||
778 | * @iocb: (unused) | ||
779 | * @m: descriptor for message info | ||
780 | * @buf_len: total size of user buffer area | ||
781 | * @flags: receive flags | ||
782 | * | ||
783 | * Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages. | ||
784 | * If the complete message doesn't fit in user area, truncate it. | ||
785 | * | ||
786 | * Returns size of returned message data, errno otherwise | ||
787 | */ | ||
788 | |||
789 | static int recv_msg(struct kiocb *iocb, struct socket *sock, | ||
790 | struct msghdr *m, size_t buf_len, int flags) | ||
791 | { | ||
792 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
793 | struct sk_buff *buf; | ||
794 | struct tipc_msg *msg; | ||
795 | unsigned int q_len; | ||
796 | unsigned int sz; | ||
797 | u32 err; | ||
798 | int res; | ||
799 | |||
800 | /* Currently doesn't support receiving into multiple iovec entries */ | ||
801 | |||
802 | if (m->msg_iovlen != 1) | ||
803 | return -EOPNOTSUPP; | ||
804 | |||
805 | /* Catch invalid receive attempts */ | ||
806 | |||
807 | if (unlikely(!buf_len)) | ||
808 | return -EINVAL; | ||
809 | |||
810 | if (sock->type == SOCK_SEQPACKET) { | ||
811 | if (unlikely(sock->state == SS_UNCONNECTED)) | ||
812 | return -ENOTCONN; | ||
813 | if (unlikely((sock->state == SS_DISCONNECTING) && | ||
814 | (skb_queue_len(&sock->sk->sk_receive_queue) == 0))) | ||
815 | return -ENOTCONN; | ||
816 | } | ||
817 | |||
818 | /* Look for a message in receive queue; wait if necessary */ | ||
819 | |||
820 | if (unlikely(down_interruptible(&tsock->sem))) | ||
821 | return -ERESTARTSYS; | ||
822 | |||
823 | restart: | ||
824 | if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && | ||
825 | (flags & MSG_DONTWAIT))) { | ||
826 | res = -EWOULDBLOCK; | ||
827 | goto exit; | ||
828 | } | ||
829 | |||
830 | if ((res = wait_event_interruptible( | ||
831 | *sock->sk->sk_sleep, | ||
832 | ((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) || | ||
833 | (sock->state == SS_DISCONNECTING))) )) { | ||
834 | goto exit; | ||
835 | } | ||
836 | |||
837 | /* Catch attempt to receive on an already terminated connection */ | ||
838 | /* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */ | ||
839 | |||
840 | if (!q_len) { | ||
841 | res = -ENOTCONN; | ||
842 | goto exit; | ||
843 | } | ||
844 | |||
845 | /* Get access to first message in receive queue */ | ||
846 | |||
847 | buf = skb_peek(&sock->sk->sk_receive_queue); | ||
848 | msg = buf_msg(buf); | ||
849 | sz = msg_data_sz(msg); | ||
850 | err = msg_errcode(msg); | ||
851 | |||
852 | /* Complete connection setup for an implied connect */ | ||
853 | |||
854 | if (unlikely(sock->state == SS_CONNECTING)) { | ||
855 | if ((res = auto_connect(sock, tsock, msg))) | ||
856 | goto exit; | ||
857 | } | ||
858 | |||
859 | /* Discard an empty non-errored message & try again */ | ||
860 | |||
861 | if ((!sz) && (!err)) { | ||
862 | advance_queue(tsock); | ||
863 | goto restart; | ||
864 | } | ||
865 | |||
866 | /* Capture sender's address (optional) */ | ||
867 | |||
868 | set_orig_addr(m, msg); | ||
869 | |||
870 | /* Capture ancillary data (optional) */ | ||
871 | |||
872 | if ((res = anc_data_recv(m, msg, tsock->p))) | ||
873 | goto exit; | ||
874 | |||
875 | /* Capture message data (if valid) & compute return value (always) */ | ||
876 | |||
877 | if (!err) { | ||
878 | if (unlikely(buf_len < sz)) { | ||
879 | sz = buf_len; | ||
880 | m->msg_flags |= MSG_TRUNC; | ||
881 | } | ||
882 | if (unlikely(copy_to_user(m->msg_iov->iov_base, msg_data(msg), | ||
883 | sz))) { | ||
884 | res = -EFAULT; | ||
885 | goto exit; | ||
886 | } | ||
887 | res = sz; | ||
888 | } else { | ||
889 | if ((sock->state == SS_READY) || | ||
890 | ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)) | ||
891 | res = 0; | ||
892 | else | ||
893 | res = -ECONNRESET; | ||
894 | } | ||
895 | |||
896 | /* Consume received message (optional) */ | ||
897 | |||
898 | if (likely(!(flags & MSG_PEEK))) { | ||
899 | if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) | ||
900 | tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked); | ||
901 | advance_queue(tsock); | ||
902 | } | ||
903 | exit: | ||
904 | up(&tsock->sem); | ||
905 | return res; | ||
906 | } | ||
907 | |||
908 | /** | ||
909 | * recv_stream - receive stream-oriented data | ||
910 | * @iocb: (unused) | ||
911 | * @m: descriptor for message info | ||
912 | * @buf_len: total size of user buffer area | ||
913 | * @flags: receive flags | ||
914 | * | ||
915 | * Used for SOCK_STREAM messages only. If not enough data is available | ||
916 | * will optionally wait for more; never truncates data. | ||
917 | * | ||
918 | * Returns size of returned message data, errno otherwise | ||
919 | */ | ||
920 | |||
921 | static int recv_stream(struct kiocb *iocb, struct socket *sock, | ||
922 | struct msghdr *m, size_t buf_len, int flags) | ||
923 | { | ||
924 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
925 | struct sk_buff *buf; | ||
926 | struct tipc_msg *msg; | ||
927 | unsigned int q_len; | ||
928 | unsigned int sz; | ||
929 | int sz_to_copy; | ||
930 | int sz_copied = 0; | ||
931 | int needed; | ||
932 | char *crs = m->msg_iov->iov_base; | ||
933 | unsigned char *buf_crs; | ||
934 | u32 err; | ||
935 | int res; | ||
936 | |||
937 | /* Currently doesn't support receiving into multiple iovec entries */ | ||
938 | |||
939 | if (m->msg_iovlen != 1) | ||
940 | return -EOPNOTSUPP; | ||
941 | |||
942 | /* Catch invalid receive attempts */ | ||
943 | |||
944 | if (unlikely(!buf_len)) | ||
945 | return -EINVAL; | ||
946 | |||
947 | if (unlikely(sock->state == SS_DISCONNECTING)) { | ||
948 | if (skb_queue_len(&sock->sk->sk_receive_queue) == 0) | ||
949 | return -ENOTCONN; | ||
950 | } else if (unlikely(sock->state != SS_CONNECTED)) | ||
951 | return -ENOTCONN; | ||
952 | |||
953 | /* Look for a message in receive queue; wait if necessary */ | ||
954 | |||
955 | if (unlikely(down_interruptible(&tsock->sem))) | ||
956 | return -ERESTARTSYS; | ||
957 | |||
958 | restart: | ||
959 | if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && | ||
960 | (flags & MSG_DONTWAIT))) { | ||
961 | res = (sz_copied == 0) ? -EWOULDBLOCK : 0; | ||
962 | goto exit; | ||
963 | } | ||
964 | |||
965 | if ((res = wait_event_interruptible( | ||
966 | *sock->sk->sk_sleep, | ||
967 | ((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) || | ||
968 | (sock->state == SS_DISCONNECTING))) )) { | ||
969 | goto exit; | ||
970 | } | ||
971 | |||
972 | /* Catch attempt to receive on an already terminated connection */ | ||
973 | /* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */ | ||
974 | |||
975 | if (!q_len) { | ||
976 | res = -ENOTCONN; | ||
977 | goto exit; | ||
978 | } | ||
979 | |||
980 | /* Get access to first message in receive queue */ | ||
981 | |||
982 | buf = skb_peek(&sock->sk->sk_receive_queue); | ||
983 | msg = buf_msg(buf); | ||
984 | sz = msg_data_sz(msg); | ||
985 | err = msg_errcode(msg); | ||
986 | |||
987 | /* Discard an empty non-errored message & try again */ | ||
988 | |||
989 | if ((!sz) && (!err)) { | ||
990 | advance_queue(tsock); | ||
991 | goto restart; | ||
992 | } | ||
993 | |||
994 | /* Optionally capture sender's address & ancillary data of first msg */ | ||
995 | |||
996 | if (sz_copied == 0) { | ||
997 | set_orig_addr(m, msg); | ||
998 | if ((res = anc_data_recv(m, msg, tsock->p))) | ||
999 | goto exit; | ||
1000 | } | ||
1001 | |||
1002 | /* Capture message data (if valid) & compute return value (always) */ | ||
1003 | |||
1004 | if (!err) { | ||
1005 | buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle); | ||
1006 | sz = buf->tail - buf_crs; | ||
1007 | |||
1008 | needed = (buf_len - sz_copied); | ||
1009 | sz_to_copy = (sz <= needed) ? sz : needed; | ||
1010 | if (unlikely(copy_to_user(crs, buf_crs, sz_to_copy))) { | ||
1011 | res = -EFAULT; | ||
1012 | goto exit; | ||
1013 | } | ||
1014 | sz_copied += sz_to_copy; | ||
1015 | |||
1016 | if (sz_to_copy < sz) { | ||
1017 | if (!(flags & MSG_PEEK)) | ||
1018 | TIPC_SKB_CB(buf)->handle = buf_crs + sz_to_copy; | ||
1019 | goto exit; | ||
1020 | } | ||
1021 | |||
1022 | crs += sz_to_copy; | ||
1023 | } else { | ||
1024 | if (sz_copied != 0) | ||
1025 | goto exit; /* can't add error msg to valid data */ | ||
1026 | |||
1027 | if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control) | ||
1028 | res = 0; | ||
1029 | else | ||
1030 | res = -ECONNRESET; | ||
1031 | } | ||
1032 | |||
1033 | /* Consume received message (optional) */ | ||
1034 | |||
1035 | if (likely(!(flags & MSG_PEEK))) { | ||
1036 | if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) | ||
1037 | tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked); | ||
1038 | advance_queue(tsock); | ||
1039 | } | ||
1040 | |||
1041 | /* Loop around if more data is required */ | ||
1042 | |||
1043 | if ((sz_copied < buf_len) /* didn't get all requested data */ | ||
1044 | && (flags & MSG_WAITALL) /* ... and need to wait for more */ | ||
1045 | && (!(flags & MSG_PEEK)) /* ... and aren't just peeking at data */ | ||
1046 | && (!err) /* ... and haven't reached a FIN */ | ||
1047 | ) | ||
1048 | goto restart; | ||
1049 | |||
1050 | exit: | ||
1051 | up(&tsock->sem); | ||
1052 | return res ? res : sz_copied; | ||
1053 | } | ||
1054 | |||
1055 | /** | ||
1056 | * queue_overloaded - test if queue overload condition exists | ||
1057 | * @queue_size: current size of queue | ||
1058 | * @base: nominal maximum size of queue | ||
1059 | * @msg: message to be added to queue | ||
1060 | * | ||
1061 | * Returns 1 if queue is currently overloaded, 0 otherwise | ||
1062 | */ | ||
1063 | |||
1064 | static int queue_overloaded(u32 queue_size, u32 base, struct tipc_msg *msg) | ||
1065 | { | ||
1066 | u32 threshold; | ||
1067 | u32 imp = msg_importance(msg); | ||
1068 | |||
1069 | if (imp == TIPC_LOW_IMPORTANCE) | ||
1070 | threshold = base; | ||
1071 | else if (imp == TIPC_MEDIUM_IMPORTANCE) | ||
1072 | threshold = base * 2; | ||
1073 | else if (imp == TIPC_HIGH_IMPORTANCE) | ||
1074 | threshold = base * 100; | ||
1075 | else | ||
1076 | return 0; | ||
1077 | |||
1078 | if (msg_connected(msg)) | ||
1079 | threshold *= 4; | ||
1080 | |||
1081 | return (queue_size > threshold); | ||
1082 | } | ||
1083 | |||
1084 | /** | ||
1085 | * async_disconnect - wrapper function used to disconnect port | ||
1086 | * @portref: TIPC port reference (passed as pointer-sized value) | ||
1087 | */ | ||
1088 | |||
1089 | static void async_disconnect(unsigned long portref) | ||
1090 | { | ||
1091 | tipc_disconnect((u32)portref); | ||
1092 | } | ||
1093 | |||
1094 | /** | ||
1095 | * dispatch - handle arriving message | ||
1096 | * @tport: TIPC port that received message | ||
1097 | * @buf: message | ||
1098 | * | ||
1099 | * Called with port locked. Must not take socket lock to avoid deadlock risk. | ||
1100 | * | ||
1101 | * Returns TIPC error status code (TIPC_OK if message is not to be rejected) | ||
1102 | */ | ||
1103 | |||
1104 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) | ||
1105 | { | ||
1106 | struct tipc_msg *msg = buf_msg(buf); | ||
1107 | struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle; | ||
1108 | struct socket *sock; | ||
1109 | u32 recv_q_len; | ||
1110 | |||
1111 | /* Reject message if socket is closing */ | ||
1112 | |||
1113 | if (!tsock) | ||
1114 | return TIPC_ERR_NO_PORT; | ||
1115 | |||
1116 | /* Reject message if it is wrong sort of message for socket */ | ||
1117 | |||
1118 | /* | ||
1119 | * WOULD IT BE BETTER TO JUST DISCARD THESE MESSAGES INSTEAD? | ||
1120 | * "NO PORT" ISN'T REALLY THE RIGHT ERROR CODE, AND THERE MAY | ||
1121 | * BE SECURITY IMPLICATIONS INHERENT IN REJECTING INVALID TRAFFIC | ||
1122 | */ | ||
1123 | sock = tsock->sk.sk_socket; | ||
1124 | if (sock->state == SS_READY) { | ||
1125 | if (msg_connected(msg)) { | ||
1126 | msg_dbg(msg, "dispatch filter 1\n"); | ||
1127 | return TIPC_ERR_NO_PORT; | ||
1128 | } | ||
1129 | } else { | ||
1130 | if (msg_mcast(msg)) { | ||
1131 | msg_dbg(msg, "dispatch filter 2\n"); | ||
1132 | return TIPC_ERR_NO_PORT; | ||
1133 | } | ||
1134 | if (sock->state == SS_CONNECTED) { | ||
1135 | if (!msg_connected(msg)) { | ||
1136 | msg_dbg(msg, "dispatch filter 3\n"); | ||
1137 | return TIPC_ERR_NO_PORT; | ||
1138 | } | ||
1139 | } | ||
1140 | else if (sock->state == SS_CONNECTING) { | ||
1141 | if (!msg_connected(msg) && (msg_errcode(msg) == 0)) { | ||
1142 | msg_dbg(msg, "dispatch filter 4\n"); | ||
1143 | return TIPC_ERR_NO_PORT; | ||
1144 | } | ||
1145 | } | ||
1146 | else if (sock->state == SS_LISTENING) { | ||
1147 | if (msg_connected(msg) || msg_errcode(msg)) { | ||
1148 | msg_dbg(msg, "dispatch filter 5\n"); | ||
1149 | return TIPC_ERR_NO_PORT; | ||
1150 | } | ||
1151 | } | ||
1152 | else if (sock->state == SS_DISCONNECTING) { | ||
1153 | msg_dbg(msg, "dispatch filter 6\n"); | ||
1154 | return TIPC_ERR_NO_PORT; | ||
1155 | } | ||
1156 | else /* (sock->state == SS_UNCONNECTED) */ { | ||
1157 | if (msg_connected(msg) || msg_errcode(msg)) { | ||
1158 | msg_dbg(msg, "dispatch filter 7\n"); | ||
1159 | return TIPC_ERR_NO_PORT; | ||
1160 | } | ||
1161 | } | ||
1162 | } | ||
1163 | |||
1164 | /* Reject message if there isn't room to queue it */ | ||
1165 | |||
1166 | if (unlikely((u32)atomic_read(&tipc_queue_size) > | ||
1167 | OVERLOAD_LIMIT_BASE)) { | ||
1168 | if (queue_overloaded(atomic_read(&tipc_queue_size), | ||
1169 | OVERLOAD_LIMIT_BASE, msg)) | ||
1170 | return TIPC_ERR_OVERLOAD; | ||
1171 | } | ||
1172 | recv_q_len = skb_queue_len(&tsock->sk.sk_receive_queue); | ||
1173 | if (unlikely(recv_q_len > (OVERLOAD_LIMIT_BASE / 2))) { | ||
1174 | if (queue_overloaded(recv_q_len, | ||
1175 | OVERLOAD_LIMIT_BASE / 2, msg)) | ||
1176 | return TIPC_ERR_OVERLOAD; | ||
1177 | } | ||
1178 | |||
1179 | /* Initiate connection termination for an incoming 'FIN' */ | ||
1180 | |||
1181 | if (unlikely(msg_errcode(msg) && (sock->state == SS_CONNECTED))) { | ||
1182 | sock->state = SS_DISCONNECTING; | ||
1183 | /* Note: Use signal since port lock is already taken! */ | ||
1184 | k_signal((Handler)async_disconnect, tport->ref); | ||
1185 | } | ||
1186 | |||
1187 | /* Enqueue message (finally!) */ | ||
1188 | |||
1189 | msg_dbg(msg,"<DISP<: "); | ||
1190 | TIPC_SKB_CB(buf)->handle = msg_data(msg); | ||
1191 | atomic_inc(&tipc_queue_size); | ||
1192 | skb_queue_tail(&sock->sk->sk_receive_queue, buf); | ||
1193 | |||
1194 | wake_up_interruptible(sock->sk->sk_sleep); | ||
1195 | return TIPC_OK; | ||
1196 | } | ||
1197 | |||
1198 | /** | ||
1199 | * wakeupdispatch - wake up port after congestion | ||
1200 | * @tport: port to wakeup | ||
1201 | * | ||
1202 | * Called with port lock on. | ||
1203 | */ | ||
1204 | |||
1205 | static void wakeupdispatch(struct tipc_port *tport) | ||
1206 | { | ||
1207 | struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle; | ||
1208 | |||
1209 | wake_up_interruptible(tsock->sk.sk_sleep); | ||
1210 | } | ||
1211 | |||
1212 | /** | ||
1213 | * connect - establish a connection to another TIPC port | ||
1214 | * @sock: socket structure | ||
1215 | * @dest: socket address for destination port | ||
1216 | * @destlen: size of socket address data structure | ||
1217 | * @flags: (unused) | ||
1218 | * | ||
1219 | * Returns 0 on success, errno otherwise | ||
1220 | */ | ||
1221 | |||
1222 | static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | ||
1223 | int flags) | ||
1224 | { | ||
1225 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
1226 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; | ||
1227 | struct msghdr m = {0,}; | ||
1228 | struct sk_buff *buf; | ||
1229 | struct tipc_msg *msg; | ||
1230 | int res; | ||
1231 | |||
1232 | /* For now, TIPC does not allow use of connect() with DGRAM or RDM types */ | ||
1233 | |||
1234 | if (sock->state == SS_READY) | ||
1235 | return -EOPNOTSUPP; | ||
1236 | |||
1237 | /* MOVE THE REST OF THIS ERROR CHECKING TO send_msg()? */ | ||
1238 | if (sock->state == SS_LISTENING) | ||
1239 | return -EOPNOTSUPP; | ||
1240 | if (sock->state == SS_CONNECTING) | ||
1241 | return -EALREADY; | ||
1242 | if (sock->state != SS_UNCONNECTED) | ||
1243 | return -EISCONN; | ||
1244 | |||
1245 | if ((dst->family != AF_TIPC) || | ||
1246 | ((dst->addrtype != TIPC_ADDR_NAME) && (dst->addrtype != TIPC_ADDR_ID))) | ||
1247 | return -EINVAL; | ||
1248 | |||
1249 | /* Send a 'SYN-' to destination */ | ||
1250 | |||
1251 | m.msg_name = dest; | ||
1252 | if ((res = send_msg(0, sock, &m, 0)) < 0) { | ||
1253 | sock->state = SS_DISCONNECTING; | ||
1254 | return res; | ||
1255 | } | ||
1256 | |||
1257 | if (down_interruptible(&tsock->sem)) | ||
1258 | return -ERESTARTSYS; | ||
1259 | |||
1260 | /* Wait for destination's 'ACK' response */ | ||
1261 | |||
1262 | res = wait_event_interruptible_timeout(*sock->sk->sk_sleep, | ||
1263 | skb_queue_len(&sock->sk->sk_receive_queue), | ||
1264 | sock->sk->sk_rcvtimeo); | ||
1265 | buf = skb_peek(&sock->sk->sk_receive_queue); | ||
1266 | if (res > 0) { | ||
1267 | msg = buf_msg(buf); | ||
1268 | res = auto_connect(sock, tsock, msg); | ||
1269 | if (!res) { | ||
1270 | if (dst->addrtype == TIPC_ADDR_NAME) { | ||
1271 | tsock->p->conn_type = dst->addr.name.name.type; | ||
1272 | tsock->p->conn_instance = dst->addr.name.name.instance; | ||
1273 | } | ||
1274 | if (!msg_data_sz(msg)) | ||
1275 | advance_queue(tsock); | ||
1276 | } | ||
1277 | } else { | ||
1278 | if (res == 0) { | ||
1279 | res = -ETIMEDOUT; | ||
1280 | } else | ||
1281 | { /* leave "res" unchanged */ } | ||
1282 | sock->state = SS_DISCONNECTING; | ||
1283 | } | ||
1284 | |||
1285 | up(&tsock->sem); | ||
1286 | return res; | ||
1287 | } | ||
1288 | |||
1289 | /** | ||
1290 | * listen - allow socket to listen for incoming connections | ||
1291 | * @sock: socket structure | ||
1292 | * @len: (unused) | ||
1293 | * | ||
1294 | * Returns 0 on success, errno otherwise | ||
1295 | */ | ||
1296 | |||
1297 | static int listen(struct socket *sock, int len) | ||
1298 | { | ||
1299 | /* REQUIRES SOCKET LOCKING OF SOME SORT? */ | ||
1300 | |||
1301 | if (sock->state == SS_READY) | ||
1302 | return -EOPNOTSUPP; | ||
1303 | if (sock->state != SS_UNCONNECTED) | ||
1304 | return -EINVAL; | ||
1305 | sock->state = SS_LISTENING; | ||
1306 | return 0; | ||
1307 | } | ||
1308 | |||
1309 | /** | ||
1310 | * accept - wait for connection request | ||
1311 | * @sock: listening socket | ||
1312 | * @newsock: new socket that is to be connected | ||
1313 | * @flags: file-related flags associated with socket | ||
1314 | * | ||
1315 | * Returns 0 on success, errno otherwise | ||
1316 | */ | ||
1317 | |||
1318 | static int accept(struct socket *sock, struct socket *newsock, int flags) | ||
1319 | { | ||
1320 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
1321 | struct sk_buff *buf; | ||
1322 | int res = -EFAULT; | ||
1323 | |||
1324 | if (sock->state == SS_READY) | ||
1325 | return -EOPNOTSUPP; | ||
1326 | if (sock->state != SS_LISTENING) | ||
1327 | return -EINVAL; | ||
1328 | |||
1329 | if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && | ||
1330 | (flags & O_NONBLOCK))) | ||
1331 | return -EWOULDBLOCK; | ||
1332 | |||
1333 | if (down_interruptible(&tsock->sem)) | ||
1334 | return -ERESTARTSYS; | ||
1335 | |||
1336 | if (wait_event_interruptible(*sock->sk->sk_sleep, | ||
1337 | skb_queue_len(&sock->sk->sk_receive_queue))) { | ||
1338 | res = -ERESTARTSYS; | ||
1339 | goto exit; | ||
1340 | } | ||
1341 | buf = skb_peek(&sock->sk->sk_receive_queue); | ||
1342 | |||
1343 | res = tipc_create(newsock, 0); | ||
1344 | if (!res) { | ||
1345 | struct tipc_sock *new_tsock = tipc_sk(newsock->sk); | ||
1346 | struct tipc_portid id; | ||
1347 | struct tipc_msg *msg = buf_msg(buf); | ||
1348 | u32 new_ref = new_tsock->p->ref; | ||
1349 | |||
1350 | id.ref = msg_origport(msg); | ||
1351 | id.node = msg_orignode(msg); | ||
1352 | tipc_connect2port(new_ref, &id); | ||
1353 | newsock->state = SS_CONNECTED; | ||
1354 | |||
1355 | tipc_set_portimportance(new_ref, msg_importance(msg)); | ||
1356 | if (msg_named(msg)) { | ||
1357 | new_tsock->p->conn_type = msg_nametype(msg); | ||
1358 | new_tsock->p->conn_instance = msg_nameinst(msg); | ||
1359 | } | ||
1360 | |||
1361 | /* | ||
1362 | * Respond to 'SYN-' by discarding it & returning 'ACK'-. | ||
1363 | * Respond to 'SYN+' by queuing it on new socket. | ||
1364 | */ | ||
1365 | |||
1366 | msg_dbg(msg,"<ACC<: "); | ||
1367 | if (!msg_data_sz(msg)) { | ||
1368 | struct msghdr m = {0,}; | ||
1369 | |||
1370 | send_packet(0, newsock, &m, 0); | ||
1371 | advance_queue(tsock); | ||
1372 | } else { | ||
1373 | sock_lock(tsock); | ||
1374 | skb_dequeue(&sock->sk->sk_receive_queue); | ||
1375 | sock_unlock(tsock); | ||
1376 | skb_queue_head(&newsock->sk->sk_receive_queue, buf); | ||
1377 | } | ||
1378 | } | ||
1379 | exit: | ||
1380 | up(&tsock->sem); | ||
1381 | return res; | ||
1382 | } | ||
1383 | |||
1384 | /** | ||
1385 | * shutdown - shutdown socket connection | ||
1386 | * @sock: socket structure | ||
1387 | * @how: direction to close (always treated as read + write) | ||
1388 | * | ||
1389 | * Terminates connection (if necessary), then purges socket's receive queue. | ||
1390 | * | ||
1391 | * Returns 0 on success, errno otherwise | ||
1392 | */ | ||
1393 | |||
1394 | static int shutdown(struct socket *sock, int how) | ||
1395 | { | ||
1396 | struct tipc_sock* tsock = tipc_sk(sock->sk); | ||
1397 | struct sk_buff *buf; | ||
1398 | int res; | ||
1399 | |||
1400 | /* Could return -EINVAL for an invalid "how", but why bother? */ | ||
1401 | |||
1402 | if (down_interruptible(&tsock->sem)) | ||
1403 | return -ERESTARTSYS; | ||
1404 | |||
1405 | sock_lock(tsock); | ||
1406 | |||
1407 | switch (sock->state) { | ||
1408 | case SS_CONNECTED: | ||
1409 | |||
1410 | /* Send 'FIN+' or 'FIN-' message to peer */ | ||
1411 | |||
1412 | sock_unlock(tsock); | ||
1413 | restart: | ||
1414 | if ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) { | ||
1415 | atomic_dec(&tipc_queue_size); | ||
1416 | if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) { | ||
1417 | buf_discard(buf); | ||
1418 | goto restart; | ||
1419 | } | ||
1420 | tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN); | ||
1421 | } | ||
1422 | else { | ||
1423 | tipc_shutdown(tsock->p->ref); | ||
1424 | } | ||
1425 | sock_lock(tsock); | ||
1426 | |||
1427 | /* fall through */ | ||
1428 | |||
1429 | case SS_DISCONNECTING: | ||
1430 | |||
1431 | /* Discard any unreceived messages */ | ||
1432 | |||
1433 | while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) { | ||
1434 | atomic_dec(&tipc_queue_size); | ||
1435 | buf_discard(buf); | ||
1436 | } | ||
1437 | tsock->p->conn_unacked = 0; | ||
1438 | |||
1439 | /* fall through */ | ||
1440 | |||
1441 | case SS_CONNECTING: | ||
1442 | sock->state = SS_DISCONNECTING; | ||
1443 | res = 0; | ||
1444 | break; | ||
1445 | |||
1446 | default: | ||
1447 | res = -ENOTCONN; | ||
1448 | } | ||
1449 | |||
1450 | sock_unlock(tsock); | ||
1451 | |||
1452 | up(&tsock->sem); | ||
1453 | return res; | ||
1454 | } | ||
1455 | |||
1456 | /** | ||
1457 | * setsockopt - set socket option | ||
1458 | * @sock: socket structure | ||
1459 | * @lvl: option level | ||
1460 | * @opt: option identifier | ||
1461 | * @ov: pointer to new option value | ||
1462 | * @ol: length of option value | ||
1463 | * | ||
1464 | * For stream sockets only, accepts and ignores all IPPROTO_TCP options | ||
1465 | * (to ease compatibility). | ||
1466 | * | ||
1467 | * Returns 0 on success, errno otherwise | ||
1468 | */ | ||
1469 | |||
1470 | static int setsockopt(struct socket *sock, int lvl, int opt, char *ov, int ol) | ||
1471 | { | ||
1472 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
1473 | u32 value; | ||
1474 | int res; | ||
1475 | |||
1476 | if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM)) | ||
1477 | return 0; | ||
1478 | if (lvl != SOL_TIPC) | ||
1479 | return -ENOPROTOOPT; | ||
1480 | if (ol < sizeof(value)) | ||
1481 | return -EINVAL; | ||
1482 | if ((res = get_user(value, (u32 *)ov))) | ||
1483 | return res; | ||
1484 | |||
1485 | if (down_interruptible(&tsock->sem)) | ||
1486 | return -ERESTARTSYS; | ||
1487 | |||
1488 | switch (opt) { | ||
1489 | case TIPC_IMPORTANCE: | ||
1490 | res = tipc_set_portimportance(tsock->p->ref, value); | ||
1491 | break; | ||
1492 | case TIPC_SRC_DROPPABLE: | ||
1493 | if (sock->type != SOCK_STREAM) | ||
1494 | res = tipc_set_portunreliable(tsock->p->ref, value); | ||
1495 | else | ||
1496 | res = -ENOPROTOOPT; | ||
1497 | break; | ||
1498 | case TIPC_DEST_DROPPABLE: | ||
1499 | res = tipc_set_portunreturnable(tsock->p->ref, value); | ||
1500 | break; | ||
1501 | case TIPC_CONN_TIMEOUT: | ||
1502 | sock->sk->sk_rcvtimeo = (value * HZ / 1000); | ||
1503 | break; | ||
1504 | default: | ||
1505 | res = -EINVAL; | ||
1506 | } | ||
1507 | |||
1508 | up(&tsock->sem); | ||
1509 | return res; | ||
1510 | } | ||
1511 | |||
1512 | /** | ||
1513 | * getsockopt - get socket option | ||
1514 | * @sock: socket structure | ||
1515 | * @lvl: option level | ||
1516 | * @opt: option identifier | ||
1517 | * @ov: receptacle for option value | ||
1518 | * @ol: receptacle for length of option value | ||
1519 | * | ||
1520 | * For stream sockets only, returns 0 length result for all IPPROTO_TCP options | ||
1521 | * (to ease compatibility). | ||
1522 | * | ||
1523 | * Returns 0 on success, errno otherwise | ||
1524 | */ | ||
1525 | |||
1526 | static int getsockopt(struct socket *sock, int lvl, int opt, char *ov, int *ol) | ||
1527 | { | ||
1528 | struct tipc_sock *tsock = tipc_sk(sock->sk); | ||
1529 | int len; | ||
1530 | u32 value; | ||
1531 | int res; | ||
1532 | |||
1533 | if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM)) | ||
1534 | return put_user(0, ol); | ||
1535 | if (lvl != SOL_TIPC) | ||
1536 | return -ENOPROTOOPT; | ||
1537 | if ((res = get_user(len, ol))) | ||
1538 | return res; | ||
1539 | |||
1540 | if (down_interruptible(&tsock->sem)) | ||
1541 | return -ERESTARTSYS; | ||
1542 | |||
1543 | switch (opt) { | ||
1544 | case TIPC_IMPORTANCE: | ||
1545 | res = tipc_portimportance(tsock->p->ref, &value); | ||
1546 | break; | ||
1547 | case TIPC_SRC_DROPPABLE: | ||
1548 | res = tipc_portunreliable(tsock->p->ref, &value); | ||
1549 | break; | ||
1550 | case TIPC_DEST_DROPPABLE: | ||
1551 | res = tipc_portunreturnable(tsock->p->ref, &value); | ||
1552 | break; | ||
1553 | case TIPC_CONN_TIMEOUT: | ||
1554 | value = (sock->sk->sk_rcvtimeo * 1000) / HZ; | ||
1555 | break; | ||
1556 | default: | ||
1557 | res = -EINVAL; | ||
1558 | } | ||
1559 | |||
1560 | if (res) { | ||
1561 | /* "get" failed */ | ||
1562 | } | ||
1563 | else if (len < sizeof(value)) { | ||
1564 | res = -EINVAL; | ||
1565 | } | ||
1566 | else if ((res = copy_to_user(ov, &value, sizeof(value)))) { | ||
1567 | /* couldn't return value */ | ||
1568 | } | ||
1569 | else { | ||
1570 | res = put_user(sizeof(value), ol); | ||
1571 | } | ||
1572 | |||
1573 | up(&tsock->sem); | ||
1574 | return res; | ||
1575 | } | ||
1576 | |||
1577 | /** | ||
1578 | * Placeholders for non-implemented functionality | ||
1579 | * | ||
1580 | * Returns error code (POSIX-compliant where defined) | ||
1581 | */ | ||
1582 | |||
1583 | static int ioctl(struct socket *s, u32 cmd, unsigned long arg) | ||
1584 | { | ||
1585 | return -EINVAL; | ||
1586 | } | ||
1587 | |||
1588 | static int no_mmap(struct file *file, struct socket *sock, | ||
1589 | struct vm_area_struct *vma) | ||
1590 | { | ||
1591 | return -EINVAL; | ||
1592 | } | ||
1593 | static ssize_t no_sendpage(struct socket *sock, struct page *page, | ||
1594 | int offset, size_t size, int flags) | ||
1595 | { | ||
1596 | return -EINVAL; | ||
1597 | } | ||
1598 | |||
1599 | static int no_skpair(struct socket *s1, struct socket *s2) | ||
1600 | { | ||
1601 | return -EOPNOTSUPP; | ||
1602 | } | ||
1603 | |||
1604 | /** | ||
1605 | * Protocol switches for the various types of TIPC sockets | ||
1606 | */ | ||
1607 | |||
1608 | static struct proto_ops msg_ops = { | ||
1609 | .owner = THIS_MODULE, | ||
1610 | .family = AF_TIPC, | ||
1611 | .release = release, | ||
1612 | .bind = bind, | ||
1613 | .connect = connect, | ||
1614 | .socketpair = no_skpair, | ||
1615 | .accept = accept, | ||
1616 | .getname = get_name, | ||
1617 | .poll = poll, | ||
1618 | .ioctl = ioctl, | ||
1619 | .listen = listen, | ||
1620 | .shutdown = shutdown, | ||
1621 | .setsockopt = setsockopt, | ||
1622 | .getsockopt = getsockopt, | ||
1623 | .sendmsg = send_msg, | ||
1624 | .recvmsg = recv_msg, | ||
1625 | .mmap = no_mmap, | ||
1626 | .sendpage = no_sendpage | ||
1627 | }; | ||
1628 | |||
1629 | static struct proto_ops packet_ops = { | ||
1630 | .owner = THIS_MODULE, | ||
1631 | .family = AF_TIPC, | ||
1632 | .release = release, | ||
1633 | .bind = bind, | ||
1634 | .connect = connect, | ||
1635 | .socketpair = no_skpair, | ||
1636 | .accept = accept, | ||
1637 | .getname = get_name, | ||
1638 | .poll = poll, | ||
1639 | .ioctl = ioctl, | ||
1640 | .listen = listen, | ||
1641 | .shutdown = shutdown, | ||
1642 | .setsockopt = setsockopt, | ||
1643 | .getsockopt = getsockopt, | ||
1644 | .sendmsg = send_packet, | ||
1645 | .recvmsg = recv_msg, | ||
1646 | .mmap = no_mmap, | ||
1647 | .sendpage = no_sendpage | ||
1648 | }; | ||
1649 | |||
1650 | static struct proto_ops stream_ops = { | ||
1651 | .owner = THIS_MODULE, | ||
1652 | .family = AF_TIPC, | ||
1653 | .release = release, | ||
1654 | .bind = bind, | ||
1655 | .connect = connect, | ||
1656 | .socketpair = no_skpair, | ||
1657 | .accept = accept, | ||
1658 | .getname = get_name, | ||
1659 | .poll = poll, | ||
1660 | .ioctl = ioctl, | ||
1661 | .listen = listen, | ||
1662 | .shutdown = shutdown, | ||
1663 | .setsockopt = setsockopt, | ||
1664 | .getsockopt = getsockopt, | ||
1665 | .sendmsg = send_stream, | ||
1666 | .recvmsg = recv_stream, | ||
1667 | .mmap = no_mmap, | ||
1668 | .sendpage = no_sendpage | ||
1669 | }; | ||
1670 | |||
1671 | static struct net_proto_family tipc_family_ops = { | ||
1672 | .owner = THIS_MODULE, | ||
1673 | .family = AF_TIPC, | ||
1674 | .create = tipc_create | ||
1675 | }; | ||
1676 | |||
1677 | static struct proto tipc_proto = { | ||
1678 | .name = "TIPC", | ||
1679 | .owner = THIS_MODULE, | ||
1680 | .obj_size = sizeof(struct tipc_sock) | ||
1681 | }; | ||
1682 | |||
1683 | /** | ||
1684 | * socket_init - initialize TIPC socket interface | ||
1685 | * | ||
1686 | * Returns 0 on success, errno otherwise | ||
1687 | */ | ||
1688 | int socket_init(void) | ||
1689 | { | ||
1690 | int res; | ||
1691 | |||
1692 | res = proto_register(&tipc_proto, 1); | ||
1693 | if (res) { | ||
1694 | err("Unable to register TIPC protocol type\n"); | ||
1695 | goto out; | ||
1696 | } | ||
1697 | |||
1698 | res = sock_register(&tipc_family_ops); | ||
1699 | if (res) { | ||
1700 | err("Unable to register TIPC socket type\n"); | ||
1701 | proto_unregister(&tipc_proto); | ||
1702 | goto out; | ||
1703 | } | ||
1704 | |||
1705 | sockets_enabled = 1; | ||
1706 | out: | ||
1707 | return res; | ||
1708 | } | ||
1709 | |||
1710 | /** | ||
1711 | * sock_stop - stop TIPC socket interface | ||
1712 | */ | ||
1713 | void socket_stop(void) | ||
1714 | { | ||
1715 | if (!sockets_enabled) | ||
1716 | return; | ||
1717 | |||
1718 | sockets_enabled = 0; | ||
1719 | sock_unregister(tipc_family_ops.family); | ||
1720 | proto_unregister(&tipc_proto); | ||
1721 | } | ||
1722 | |||