blob: abadb4a846cf04a0d6fcfe842e204aec1e1b9951 [file] [log] [blame]
Jennifer Hunteac37312007-02-08 13:51:54 -08001/*
2 * linux/net/iucv/af_iucv.c
3 *
4 * IUCV protocol stack for Linux on zSeries
5 *
6 * Copyright 2006 IBM Corporation
7 *
8 * Author(s): Jennifer Hunt <jenhunt@us.ibm.com>
9 */
10
Ursula Braun8f7c5022008-12-25 13:39:47 +010011#define KMSG_COMPONENT "af_iucv"
12#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
13
Jennifer Hunteac37312007-02-08 13:51:54 -080014#include <linux/module.h>
15#include <linux/types.h>
16#include <linux/list.h>
17#include <linux/errno.h>
18#include <linux/kernel.h>
19#include <linux/sched.h>
20#include <linux/slab.h>
21#include <linux/skbuff.h>
22#include <linux/init.h>
23#include <linux/poll.h>
24#include <net/sock.h>
25#include <asm/ebcdic.h>
26#include <asm/cpcmd.h>
27#include <linux/kmod.h>
28
29#include <net/iucv/iucv.h>
30#include <net/iucv/af_iucv.h>
31
Hendrik Brueckner9d5c5d82009-04-21 23:26:22 +000032#define VERSION "1.1"
Jennifer Hunteac37312007-02-08 13:51:54 -080033
34static char iucv_userid[80];
35
36static struct proto_ops iucv_sock_ops;
37
38static struct proto iucv_proto = {
39 .name = "AF_IUCV",
40 .owner = THIS_MODULE,
41 .obj_size = sizeof(struct iucv_sock),
42};
43
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +000044/* special AF_IUCV IPRM messages */
45static const u8 iprm_shutdown[8] =
46 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
47
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +000048#define TRGCLS_SIZE (sizeof(((struct iucv_message *)0)->class))
49
50/* macros to set/get socket control buffer at correct offset */
51#define CB_TAG(skb) ((skb)->cb) /* iucv message tag */
52#define CB_TAG_LEN (sizeof(((struct iucv_message *) 0)->tag))
53#define CB_TRGCLS(skb) ((skb)->cb + CB_TAG_LEN) /* iucv msg target class */
54#define CB_TRGCLS_LEN (TRGCLS_SIZE)
55
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +000056#define __iucv_sock_wait(sk, condition, timeo, ret) \
57do { \
58 DEFINE_WAIT(__wait); \
59 long __timeo = timeo; \
60 ret = 0; \
61 while (!(condition)) { \
62 prepare_to_wait(sk->sk_sleep, &__wait, TASK_INTERRUPTIBLE); \
63 if (!__timeo) { \
64 ret = -EAGAIN; \
65 break; \
66 } \
67 if (signal_pending(current)) { \
68 ret = sock_intr_errno(__timeo); \
69 break; \
70 } \
71 release_sock(sk); \
72 __timeo = schedule_timeout(__timeo); \
73 lock_sock(sk); \
74 ret = sock_error(sk); \
75 if (ret) \
76 break; \
77 } \
78 finish_wait(sk->sk_sleep, &__wait); \
79} while (0)
80
81#define iucv_sock_wait(sk, condition, timeo) \
82({ \
83 int __ret = 0; \
84 if (!(condition)) \
85 __iucv_sock_wait(sk, condition, timeo, __ret); \
86 __ret; \
87})
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +000088
Heiko Carstens57f20442007-10-08 02:02:52 -070089static void iucv_sock_kill(struct sock *sk);
90static void iucv_sock_close(struct sock *sk);
91
Jennifer Hunteac37312007-02-08 13:51:54 -080092/* Call Back functions */
93static void iucv_callback_rx(struct iucv_path *, struct iucv_message *);
94static void iucv_callback_txdone(struct iucv_path *, struct iucv_message *);
95static void iucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
Heiko Carstensda99f052007-05-04 12:23:27 -070096static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8],
97 u8 ipuser[16]);
Jennifer Hunteac37312007-02-08 13:51:54 -080098static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
Hendrik Brueckneraf88b522009-04-21 23:26:21 +000099static void iucv_callback_shutdown(struct iucv_path *, u8 ipuser[16]);
Jennifer Hunteac37312007-02-08 13:51:54 -0800100
101static struct iucv_sock_list iucv_sk_list = {
Robert P. J. Day3db8ce32008-04-10 02:11:24 -0700102 .lock = __RW_LOCK_UNLOCKED(iucv_sk_list.lock),
Jennifer Hunteac37312007-02-08 13:51:54 -0800103 .autobind_name = ATOMIC_INIT(0)
104};
105
106static struct iucv_handler af_iucv_handler = {
107 .path_pending = iucv_callback_connreq,
108 .path_complete = iucv_callback_connack,
109 .path_severed = iucv_callback_connrej,
110 .message_pending = iucv_callback_rx,
Hendrik Brueckneraf88b522009-04-21 23:26:21 +0000111 .message_complete = iucv_callback_txdone,
112 .path_quiesced = iucv_callback_shutdown,
Jennifer Hunteac37312007-02-08 13:51:54 -0800113};
114
115static inline void high_nmcpy(unsigned char *dst, char *src)
116{
117 memcpy(dst, src, 8);
118}
119
120static inline void low_nmcpy(unsigned char *dst, char *src)
121{
122 memcpy(&dst[8], src, 8);
123}
124
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000125/**
126 * iucv_msg_length() - Returns the length of an iucv message.
127 * @msg: Pointer to struct iucv_message, MUST NOT be NULL
128 *
129 * The function returns the length of the specified iucv message @msg of data
130 * stored in a buffer and of data stored in the parameter list (PRMDATA).
131 *
132 * For IUCV_IPRMDATA, AF_IUCV uses the following convention to transport socket
133 * data:
134 * PRMDATA[0..6] socket data (max 7 bytes);
135 * PRMDATA[7] socket data length value (len is 0xff - PRMDATA[7])
136 *
137 * The socket data length is computed by substracting the socket data length
138 * value from 0xFF.
139 * If the socket data len is greater 7, then PRMDATA can be used for special
140 * notifications (see iucv_sock_shutdown); and further,
141 * if the socket data len is > 7, the function returns 8.
142 *
143 * Use this function to allocate socket buffers to store iucv message data.
144 */
145static inline size_t iucv_msg_length(struct iucv_message *msg)
146{
147 size_t datalen;
148
149 if (msg->flags & IUCV_IPRMDATA) {
150 datalen = 0xff - msg->rmmsg[7];
151 return (datalen < 8) ? datalen : 8;
152 }
153 return msg->length;
154}
155
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +0000156/**
157 * iucv_sock_in_state() - check for specific states
158 * @sk: sock structure
159 * @state: first iucv sk state
160 * @state: second iucv sk state
161 *
162 * Returns true if the socket in either in the first or second state.
163 */
164static int iucv_sock_in_state(struct sock *sk, int state, int state2)
165{
166 return (sk->sk_state == state || sk->sk_state == state2);
167}
168
169/**
170 * iucv_below_msglim() - function to check if messages can be sent
171 * @sk: sock structure
172 *
173 * Returns true if the send queue length is lower than the message limit.
174 * Always returns true if the socket is not connected (no iucv path for
175 * checking the message limit).
176 */
177static inline int iucv_below_msglim(struct sock *sk)
178{
179 struct iucv_sock *iucv = iucv_sk(sk);
180
181 if (sk->sk_state != IUCV_CONNECTED)
182 return 1;
183 return (skb_queue_len(&iucv->send_skb_q) < iucv->path->msglim);
184}
185
186/**
187 * iucv_sock_wake_msglim() - Wake up thread waiting on msg limit
188 */
189static void iucv_sock_wake_msglim(struct sock *sk)
190{
191 read_lock(&sk->sk_callback_lock);
192 if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
193 wake_up_interruptible_all(sk->sk_sleep);
194 sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
195 read_unlock(&sk->sk_callback_lock);
196}
197
Jennifer Hunteac37312007-02-08 13:51:54 -0800198/* Timers */
199static void iucv_sock_timeout(unsigned long arg)
200{
201 struct sock *sk = (struct sock *)arg;
202
203 bh_lock_sock(sk);
204 sk->sk_err = ETIMEDOUT;
205 sk->sk_state_change(sk);
206 bh_unlock_sock(sk);
207
208 iucv_sock_kill(sk);
209 sock_put(sk);
210}
211
212static void iucv_sock_clear_timer(struct sock *sk)
213{
214 sk_stop_timer(sk, &sk->sk_timer);
215}
216
Jennifer Hunteac37312007-02-08 13:51:54 -0800217static struct sock *__iucv_get_sock_by_name(char *nm)
218{
219 struct sock *sk;
220 struct hlist_node *node;
221
222 sk_for_each(sk, node, &iucv_sk_list.head)
223 if (!memcmp(&iucv_sk(sk)->src_name, nm, 8))
224 return sk;
225
226 return NULL;
227}
228
229static void iucv_sock_destruct(struct sock *sk)
230{
231 skb_queue_purge(&sk->sk_receive_queue);
232 skb_queue_purge(&sk->sk_write_queue);
233}
234
235/* Cleanup Listen */
236static void iucv_sock_cleanup_listen(struct sock *parent)
237{
238 struct sock *sk;
239
240 /* Close non-accepted connections */
241 while ((sk = iucv_accept_dequeue(parent, NULL))) {
242 iucv_sock_close(sk);
243 iucv_sock_kill(sk);
244 }
245
246 parent->sk_state = IUCV_CLOSED;
247 sock_set_flag(parent, SOCK_ZAPPED);
248}
249
250/* Kill socket */
251static void iucv_sock_kill(struct sock *sk)
252{
253 if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
254 return;
255
256 iucv_sock_unlink(&iucv_sk_list, sk);
257 sock_set_flag(sk, SOCK_DEAD);
258 sock_put(sk);
259}
260
261/* Close an IUCV socket */
262static void iucv_sock_close(struct sock *sk)
263{
264 unsigned char user_data[16];
265 struct iucv_sock *iucv = iucv_sk(sk);
266 int err;
Jennifer Hunt561e0362007-05-04 12:22:07 -0700267 unsigned long timeo;
Jennifer Hunteac37312007-02-08 13:51:54 -0800268
269 iucv_sock_clear_timer(sk);
270 lock_sock(sk);
271
Heiko Carstensda99f052007-05-04 12:23:27 -0700272 switch (sk->sk_state) {
Jennifer Hunteac37312007-02-08 13:51:54 -0800273 case IUCV_LISTEN:
274 iucv_sock_cleanup_listen(sk);
275 break;
276
277 case IUCV_CONNECTED:
278 case IUCV_DISCONN:
279 err = 0;
Jennifer Hunt561e0362007-05-04 12:22:07 -0700280
281 sk->sk_state = IUCV_CLOSING;
282 sk->sk_state_change(sk);
283
Heiko Carstensda99f052007-05-04 12:23:27 -0700284 if (!skb_queue_empty(&iucv->send_skb_q)) {
Jennifer Hunt561e0362007-05-04 12:22:07 -0700285 if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
286 timeo = sk->sk_lingertime;
287 else
288 timeo = IUCV_DISCONN_TIMEOUT;
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +0000289 err = iucv_sock_wait(sk,
290 iucv_sock_in_state(sk, IUCV_CLOSED, 0),
291 timeo);
Jennifer Hunt561e0362007-05-04 12:22:07 -0700292 }
293
Ursula Braunbbe188c2009-04-21 06:04:20 +0000294 case IUCV_CLOSING: /* fall through */
Jennifer Hunt561e0362007-05-04 12:22:07 -0700295 sk->sk_state = IUCV_CLOSED;
296 sk->sk_state_change(sk);
297
Jennifer Hunteac37312007-02-08 13:51:54 -0800298 if (iucv->path) {
299 low_nmcpy(user_data, iucv->src_name);
300 high_nmcpy(user_data, iucv->dst_name);
301 ASCEBC(user_data, sizeof(user_data));
302 err = iucv_path_sever(iucv->path, user_data);
303 iucv_path_free(iucv->path);
304 iucv->path = NULL;
305 }
306
Jennifer Hunteac37312007-02-08 13:51:54 -0800307 sk->sk_err = ECONNRESET;
308 sk->sk_state_change(sk);
309
310 skb_queue_purge(&iucv->send_skb_q);
Jennifer Hunt561e0362007-05-04 12:22:07 -0700311 skb_queue_purge(&iucv->backlog_skb_q);
Jennifer Hunteac37312007-02-08 13:51:54 -0800312
313 sock_set_flag(sk, SOCK_ZAPPED);
314 break;
315
316 default:
317 sock_set_flag(sk, SOCK_ZAPPED);
318 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700319 }
Jennifer Hunteac37312007-02-08 13:51:54 -0800320
321 release_sock(sk);
322 iucv_sock_kill(sk);
323}
324
325static void iucv_sock_init(struct sock *sk, struct sock *parent)
326{
327 if (parent)
328 sk->sk_type = parent->sk_type;
329}
330
331static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio)
332{
333 struct sock *sk;
334
Pavel Emelyanov6257ff22007-11-01 00:39:31 -0700335 sk = sk_alloc(&init_net, PF_IUCV, prio, &iucv_proto);
Jennifer Hunteac37312007-02-08 13:51:54 -0800336 if (!sk)
337 return NULL;
338
339 sock_init_data(sock, sk);
340 INIT_LIST_HEAD(&iucv_sk(sk)->accept_q);
Ursula Braunfebca282007-07-14 19:04:25 -0700341 spin_lock_init(&iucv_sk(sk)->accept_q_lock);
Jennifer Hunteac37312007-02-08 13:51:54 -0800342 skb_queue_head_init(&iucv_sk(sk)->send_skb_q);
Ursula Braunf0703c82007-10-08 02:03:31 -0700343 INIT_LIST_HEAD(&iucv_sk(sk)->message_q.list);
344 spin_lock_init(&iucv_sk(sk)->message_q.lock);
Jennifer Hunt561e0362007-05-04 12:22:07 -0700345 skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q);
Jennifer Hunteac37312007-02-08 13:51:54 -0800346 iucv_sk(sk)->send_tag = 0;
Hendrik Brueckner9d5c5d82009-04-21 23:26:22 +0000347 iucv_sk(sk)->flags = 0;
Hendrik Brueckner09488e2e2009-04-21 23:26:27 +0000348 iucv_sk(sk)->msglimit = IUCV_QUEUELEN_DEFAULT;
Ursula Braunbbe188c2009-04-21 06:04:20 +0000349 iucv_sk(sk)->path = NULL;
350 memset(&iucv_sk(sk)->src_user_id , 0, 32);
Jennifer Hunteac37312007-02-08 13:51:54 -0800351
352 sk->sk_destruct = iucv_sock_destruct;
353 sk->sk_sndtimeo = IUCV_CONN_TIMEOUT;
354 sk->sk_allocation = GFP_DMA;
355
356 sock_reset_flag(sk, SOCK_ZAPPED);
357
358 sk->sk_protocol = proto;
359 sk->sk_state = IUCV_OPEN;
360
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800361 setup_timer(&sk->sk_timer, iucv_sock_timeout, (unsigned long)sk);
Jennifer Hunteac37312007-02-08 13:51:54 -0800362
363 iucv_sock_link(&iucv_sk_list, sk);
364 return sk;
365}
366
367/* Create an IUCV socket */
Eric W. Biederman1b8d7ae2007-10-08 23:24:22 -0700368static int iucv_sock_create(struct net *net, struct socket *sock, int protocol)
Jennifer Hunteac37312007-02-08 13:51:54 -0800369{
370 struct sock *sk;
371
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +0000372 if (protocol && protocol != PF_IUCV)
373 return -EPROTONOSUPPORT;
Jennifer Hunteac37312007-02-08 13:51:54 -0800374
375 sock->state = SS_UNCONNECTED;
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +0000376
377 switch (sock->type) {
378 case SOCK_STREAM:
379 sock->ops = &iucv_sock_ops;
380 break;
381 case SOCK_SEQPACKET:
382 /* currently, proto ops can handle both sk types */
383 sock->ops = &iucv_sock_ops;
384 break;
385 default:
386 return -ESOCKTNOSUPPORT;
387 }
Jennifer Hunteac37312007-02-08 13:51:54 -0800388
389 sk = iucv_sock_alloc(sock, protocol, GFP_KERNEL);
390 if (!sk)
391 return -ENOMEM;
392
393 iucv_sock_init(sk, NULL);
394
395 return 0;
396}
397
398void iucv_sock_link(struct iucv_sock_list *l, struct sock *sk)
399{
400 write_lock_bh(&l->lock);
401 sk_add_node(sk, &l->head);
402 write_unlock_bh(&l->lock);
403}
404
405void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *sk)
406{
407 write_lock_bh(&l->lock);
408 sk_del_node_init(sk);
409 write_unlock_bh(&l->lock);
410}
411
412void iucv_accept_enqueue(struct sock *parent, struct sock *sk)
413{
Ursula Braunfebca282007-07-14 19:04:25 -0700414 unsigned long flags;
415 struct iucv_sock *par = iucv_sk(parent);
416
Jennifer Hunteac37312007-02-08 13:51:54 -0800417 sock_hold(sk);
Ursula Braunfebca282007-07-14 19:04:25 -0700418 spin_lock_irqsave(&par->accept_q_lock, flags);
419 list_add_tail(&iucv_sk(sk)->accept_q, &par->accept_q);
420 spin_unlock_irqrestore(&par->accept_q_lock, flags);
Jennifer Hunteac37312007-02-08 13:51:54 -0800421 iucv_sk(sk)->parent = parent;
422 parent->sk_ack_backlog++;
423}
424
425void iucv_accept_unlink(struct sock *sk)
426{
Ursula Braunfebca282007-07-14 19:04:25 -0700427 unsigned long flags;
428 struct iucv_sock *par = iucv_sk(iucv_sk(sk)->parent);
429
430 spin_lock_irqsave(&par->accept_q_lock, flags);
Jennifer Hunteac37312007-02-08 13:51:54 -0800431 list_del_init(&iucv_sk(sk)->accept_q);
Ursula Braunfebca282007-07-14 19:04:25 -0700432 spin_unlock_irqrestore(&par->accept_q_lock, flags);
Jennifer Hunteac37312007-02-08 13:51:54 -0800433 iucv_sk(sk)->parent->sk_ack_backlog--;
434 iucv_sk(sk)->parent = NULL;
435 sock_put(sk);
436}
437
438struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock)
439{
440 struct iucv_sock *isk, *n;
441 struct sock *sk;
442
Heiko Carstensda99f052007-05-04 12:23:27 -0700443 list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q) {
Jennifer Hunteac37312007-02-08 13:51:54 -0800444 sk = (struct sock *) isk;
445 lock_sock(sk);
446
447 if (sk->sk_state == IUCV_CLOSED) {
Jennifer Hunteac37312007-02-08 13:51:54 -0800448 iucv_accept_unlink(sk);
Ursula Braunfebca282007-07-14 19:04:25 -0700449 release_sock(sk);
Jennifer Hunteac37312007-02-08 13:51:54 -0800450 continue;
451 }
452
453 if (sk->sk_state == IUCV_CONNECTED ||
454 sk->sk_state == IUCV_SEVERED ||
455 !newsock) {
456 iucv_accept_unlink(sk);
457 if (newsock)
458 sock_graft(sk, newsock);
459
460 if (sk->sk_state == IUCV_SEVERED)
461 sk->sk_state = IUCV_DISCONN;
462
463 release_sock(sk);
464 return sk;
465 }
466
467 release_sock(sk);
468 }
469 return NULL;
470}
471
Jennifer Hunteac37312007-02-08 13:51:54 -0800472/* Bind an unbound socket */
473static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
474 int addr_len)
475{
476 struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
477 struct sock *sk = sock->sk;
478 struct iucv_sock *iucv;
479 int err;
480
481 /* Verify the input sockaddr */
482 if (!addr || addr->sa_family != AF_IUCV)
483 return -EINVAL;
484
485 lock_sock(sk);
486 if (sk->sk_state != IUCV_OPEN) {
487 err = -EBADFD;
488 goto done;
489 }
490
491 write_lock_bh(&iucv_sk_list.lock);
492
493 iucv = iucv_sk(sk);
494 if (__iucv_get_sock_by_name(sa->siucv_name)) {
495 err = -EADDRINUSE;
496 goto done_unlock;
497 }
498 if (iucv->path) {
499 err = 0;
500 goto done_unlock;
501 }
502
503 /* Bind the socket */
504 memcpy(iucv->src_name, sa->siucv_name, 8);
505
506 /* Copy the user id */
507 memcpy(iucv->src_user_id, iucv_userid, 8);
508 sk->sk_state = IUCV_BOUND;
509 err = 0;
510
511done_unlock:
512 /* Release the socket list lock */
513 write_unlock_bh(&iucv_sk_list.lock);
514done:
515 release_sock(sk);
516 return err;
517}
518
519/* Automatically bind an unbound socket */
520static int iucv_sock_autobind(struct sock *sk)
521{
522 struct iucv_sock *iucv = iucv_sk(sk);
523 char query_buffer[80];
524 char name[12];
525 int err = 0;
526
527 /* Set the userid and name */
528 cpcmd("QUERY USERID", query_buffer, sizeof(query_buffer), &err);
529 if (unlikely(err))
530 return -EPROTO;
531
532 memcpy(iucv->src_user_id, query_buffer, 8);
533
534 write_lock_bh(&iucv_sk_list.lock);
535
536 sprintf(name, "%08x", atomic_inc_return(&iucv_sk_list.autobind_name));
537 while (__iucv_get_sock_by_name(name)) {
538 sprintf(name, "%08x",
539 atomic_inc_return(&iucv_sk_list.autobind_name));
540 }
541
542 write_unlock_bh(&iucv_sk_list.lock);
543
544 memcpy(&iucv->src_name, name, 8);
545
546 return err;
547}
548
549/* Connect an unconnected socket */
550static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
551 int alen, int flags)
552{
553 struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
554 struct sock *sk = sock->sk;
555 struct iucv_sock *iucv;
556 unsigned char user_data[16];
557 int err;
558
559 if (addr->sa_family != AF_IUCV || alen < sizeof(struct sockaddr_iucv))
560 return -EINVAL;
561
562 if (sk->sk_state != IUCV_OPEN && sk->sk_state != IUCV_BOUND)
563 return -EBADFD;
564
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +0000565 if (sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_SEQPACKET)
Jennifer Hunteac37312007-02-08 13:51:54 -0800566 return -EINVAL;
567
Jennifer Hunteac37312007-02-08 13:51:54 -0800568 if (sk->sk_state == IUCV_OPEN) {
569 err = iucv_sock_autobind(sk);
570 if (unlikely(err))
571 return err;
572 }
573
574 lock_sock(sk);
575
576 /* Set the destination information */
577 memcpy(iucv_sk(sk)->dst_user_id, sa->siucv_user_id, 8);
578 memcpy(iucv_sk(sk)->dst_name, sa->siucv_name, 8);
579
580 high_nmcpy(user_data, sa->siucv_name);
581 low_nmcpy(user_data, iucv_sk(sk)->src_name);
582 ASCEBC(user_data, sizeof(user_data));
583
584 iucv = iucv_sk(sk);
585 /* Create path. */
Hendrik Brueckner09488e2e2009-04-21 23:26:27 +0000586 iucv->path = iucv_path_alloc(iucv->msglimit,
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000587 IUCV_IPRMDATA, GFP_KERNEL);
Ursula Braund4444722008-02-07 18:07:19 -0800588 if (!iucv->path) {
589 err = -ENOMEM;
590 goto done;
591 }
Jennifer Hunteac37312007-02-08 13:51:54 -0800592 err = iucv_path_connect(iucv->path, &af_iucv_handler,
593 sa->siucv_user_id, NULL, user_data, sk);
594 if (err) {
595 iucv_path_free(iucv->path);
596 iucv->path = NULL;
Hendrik Brueckner55cdea92009-01-05 18:07:07 -0800597 switch (err) {
598 case 0x0b: /* Target communicator is not logged on */
599 err = -ENETUNREACH;
600 break;
601 case 0x0d: /* Max connections for this guest exceeded */
602 case 0x0e: /* Max connections for target guest exceeded */
603 err = -EAGAIN;
604 break;
605 case 0x0f: /* Missing IUCV authorization */
606 err = -EACCES;
607 break;
608 default:
609 err = -ECONNREFUSED;
610 break;
611 }
Jennifer Hunteac37312007-02-08 13:51:54 -0800612 goto done;
613 }
614
615 if (sk->sk_state != IUCV_CONNECTED) {
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +0000616 err = iucv_sock_wait(sk, iucv_sock_in_state(sk, IUCV_CONNECTED,
617 IUCV_DISCONN),
618 sock_sndtimeo(sk, flags & O_NONBLOCK));
Jennifer Hunteac37312007-02-08 13:51:54 -0800619 }
620
621 if (sk->sk_state == IUCV_DISCONN) {
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000622 err = -ECONNREFUSED;
Jennifer Hunteac37312007-02-08 13:51:54 -0800623 }
Ursula Braun18becbc2009-01-05 18:07:46 -0800624
625 if (err) {
626 iucv_path_sever(iucv->path, NULL);
627 iucv_path_free(iucv->path);
628 iucv->path = NULL;
629 }
630
Jennifer Hunteac37312007-02-08 13:51:54 -0800631done:
632 release_sock(sk);
633 return err;
634}
635
636/* Move a socket into listening state. */
637static int iucv_sock_listen(struct socket *sock, int backlog)
638{
639 struct sock *sk = sock->sk;
640 int err;
641
642 lock_sock(sk);
643
644 err = -EINVAL;
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +0000645 if (sk->sk_state != IUCV_BOUND)
646 goto done;
647
648 if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET)
Jennifer Hunteac37312007-02-08 13:51:54 -0800649 goto done;
650
651 sk->sk_max_ack_backlog = backlog;
652 sk->sk_ack_backlog = 0;
653 sk->sk_state = IUCV_LISTEN;
654 err = 0;
655
656done:
657 release_sock(sk);
658 return err;
659}
660
661/* Accept a pending connection */
662static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
663 int flags)
664{
665 DECLARE_WAITQUEUE(wait, current);
666 struct sock *sk = sock->sk, *nsk;
667 long timeo;
668 int err = 0;
669
Jennifer Hunt561e0362007-05-04 12:22:07 -0700670 lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
Jennifer Hunteac37312007-02-08 13:51:54 -0800671
672 if (sk->sk_state != IUCV_LISTEN) {
673 err = -EBADFD;
674 goto done;
675 }
676
677 timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
678
679 /* Wait for an incoming connection */
680 add_wait_queue_exclusive(sk->sk_sleep, &wait);
Heiko Carstensda99f052007-05-04 12:23:27 -0700681 while (!(nsk = iucv_accept_dequeue(sk, newsock))) {
Jennifer Hunteac37312007-02-08 13:51:54 -0800682 set_current_state(TASK_INTERRUPTIBLE);
683 if (!timeo) {
684 err = -EAGAIN;
685 break;
686 }
687
688 release_sock(sk);
689 timeo = schedule_timeout(timeo);
Jennifer Hunt561e0362007-05-04 12:22:07 -0700690 lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
Jennifer Hunteac37312007-02-08 13:51:54 -0800691
692 if (sk->sk_state != IUCV_LISTEN) {
693 err = -EBADFD;
694 break;
695 }
696
697 if (signal_pending(current)) {
698 err = sock_intr_errno(timeo);
699 break;
700 }
701 }
702
703 set_current_state(TASK_RUNNING);
704 remove_wait_queue(sk->sk_sleep, &wait);
705
706 if (err)
707 goto done;
708
709 newsock->state = SS_CONNECTED;
710
711done:
712 release_sock(sk);
713 return err;
714}
715
716static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
717 int *len, int peer)
718{
719 struct sockaddr_iucv *siucv = (struct sockaddr_iucv *) addr;
720 struct sock *sk = sock->sk;
721
722 addr->sa_family = AF_IUCV;
723 *len = sizeof(struct sockaddr_iucv);
724
725 if (peer) {
726 memcpy(siucv->siucv_user_id, iucv_sk(sk)->dst_user_id, 8);
727 memcpy(siucv->siucv_name, &iucv_sk(sk)->dst_name, 8);
728 } else {
729 memcpy(siucv->siucv_user_id, iucv_sk(sk)->src_user_id, 8);
730 memcpy(siucv->siucv_name, iucv_sk(sk)->src_name, 8);
731 }
732 memset(&siucv->siucv_port, 0, sizeof(siucv->siucv_port));
733 memset(&siucv->siucv_addr, 0, sizeof(siucv->siucv_addr));
734 memset(siucv->siucv_nodeid, 0, sizeof(siucv->siucv_nodeid));
735
736 return 0;
737}
738
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000739/**
740 * iucv_send_iprm() - Send socket data in parameter list of an iucv message.
741 * @path: IUCV path
742 * @msg: Pointer to a struct iucv_message
743 * @skb: The socket data to send, skb->len MUST BE <= 7
744 *
745 * Send the socket data in the parameter list in the iucv message
746 * (IUCV_IPRMDATA). The socket data is stored at index 0 to 6 in the parameter
747 * list and the socket data len at index 7 (last byte).
748 * See also iucv_msg_length().
749 *
750 * Returns the error code from the iucv_message_send() call.
751 */
752static int iucv_send_iprm(struct iucv_path *path, struct iucv_message *msg,
753 struct sk_buff *skb)
754{
755 u8 prmdata[8];
756
757 memcpy(prmdata, (void *) skb->data, skb->len);
758 prmdata[7] = 0xff - (u8) skb->len;
759 return iucv_message_send(path, msg, IUCV_IPRMDATA, 0,
760 (void *) prmdata, 8);
761}
762
Jennifer Hunteac37312007-02-08 13:51:54 -0800763static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
764 struct msghdr *msg, size_t len)
765{
766 struct sock *sk = sock->sk;
767 struct iucv_sock *iucv = iucv_sk(sk);
768 struct sk_buff *skb;
769 struct iucv_message txmsg;
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +0000770 struct cmsghdr *cmsg;
771 int cmsg_done;
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +0000772 long timeo;
Ursula Braun8f7c5022008-12-25 13:39:47 +0100773 char user_id[9];
774 char appl_id[9];
Jennifer Hunteac37312007-02-08 13:51:54 -0800775 int err;
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +0000776 int noblock = msg->msg_flags & MSG_DONTWAIT;
Jennifer Hunteac37312007-02-08 13:51:54 -0800777
778 err = sock_error(sk);
779 if (err)
780 return err;
781
782 if (msg->msg_flags & MSG_OOB)
783 return -EOPNOTSUPP;
784
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +0000785 /* SOCK_SEQPACKET: we do not support segmented records */
786 if (sk->sk_type == SOCK_SEQPACKET && !(msg->msg_flags & MSG_EOR))
787 return -EOPNOTSUPP;
788
Jennifer Hunteac37312007-02-08 13:51:54 -0800789 lock_sock(sk);
790
791 if (sk->sk_shutdown & SEND_SHUTDOWN) {
792 err = -EPIPE;
793 goto out;
794 }
795
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000796 /* Return if the socket is not in connected state */
797 if (sk->sk_state != IUCV_CONNECTED) {
798 err = -ENOTCONN;
799 goto out;
800 }
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +0000801
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000802 /* initialize defaults */
803 cmsg_done = 0; /* check for duplicate headers */
804 txmsg.class = 0;
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +0000805
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000806 /* iterate over control messages */
807 for (cmsg = CMSG_FIRSTHDR(msg); cmsg;
808 cmsg = CMSG_NXTHDR(msg, cmsg)) {
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +0000809
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000810 if (!CMSG_OK(msg, cmsg)) {
811 err = -EINVAL;
Jennifer Hunt561e0362007-05-04 12:22:07 -0700812 goto out;
Jennifer Hunteac37312007-02-08 13:51:54 -0800813 }
814
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000815 if (cmsg->cmsg_level != SOL_IUCV)
816 continue;
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000817
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000818 if (cmsg->cmsg_type & cmsg_done) {
819 err = -EINVAL;
820 goto out;
821 }
822 cmsg_done |= cmsg->cmsg_type;
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000823
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000824 switch (cmsg->cmsg_type) {
825 case SCM_IUCV_TRGCLS:
826 if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) {
827 err = -EINVAL;
828 goto out;
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000829 }
830
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000831 /* set iucv message target class */
832 memcpy(&txmsg.class,
833 (void *) CMSG_DATA(cmsg), TRGCLS_SIZE);
834
835 break;
836
837 default:
838 err = -EINVAL;
839 goto out;
840 break;
841 }
842 }
843
844 /* allocate one skb for each iucv message:
845 * this is fine for SOCK_SEQPACKET (unless we want to support
846 * segmented records using the MSG_EOR flag), but
847 * for SOCK_STREAM we might want to improve it in future */
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +0000848 skb = sock_alloc_send_skb(sk, len, noblock, &err);
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000849 if (!skb)
850 goto out;
851 if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
852 err = -EFAULT;
853 goto fail;
854 }
855
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +0000856 /* wait if outstanding messages for iucv path has reached */
857 timeo = sock_sndtimeo(sk, noblock);
858 err = iucv_sock_wait(sk, iucv_below_msglim(sk), timeo);
859 if (err)
860 goto fail;
861
862 /* return -ECONNRESET if the socket is no longer connected */
863 if (sk->sk_state != IUCV_CONNECTED) {
864 err = -ECONNRESET;
865 goto fail;
866 }
867
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000868 /* increment and save iucv message tag for msg_completion cbk */
869 txmsg.tag = iucv->send_tag++;
870 memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN);
871 skb_queue_tail(&iucv->send_skb_q, skb);
872
873 if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
874 && skb->len <= 7) {
875 err = iucv_send_iprm(iucv->path, &txmsg, skb);
876
877 /* on success: there is no message_complete callback
878 * for an IPRMDATA msg; remove skb from send queue */
879 if (err == 0) {
880 skb_unlink(skb, &iucv->send_skb_q);
881 kfree_skb(skb);
882 }
883
884 /* this error should never happen since the
885 * IUCV_IPRMDATA path flag is set... sever path */
886 if (err == 0x15) {
887 iucv_path_sever(iucv->path, NULL);
Jennifer Hunteac37312007-02-08 13:51:54 -0800888 skb_unlink(skb, &iucv->send_skb_q);
889 err = -EPIPE;
890 goto fail;
891 }
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000892 } else
893 err = iucv_message_send(iucv->path, &txmsg, 0, 0,
894 (void *) skb->data, skb->len);
895 if (err) {
896 if (err == 3) {
897 user_id[8] = 0;
898 memcpy(user_id, iucv->dst_user_id, 8);
899 appl_id[8] = 0;
900 memcpy(appl_id, iucv->dst_name, 8);
901 pr_err("Application %s on z/VM guest %s"
902 " exceeds message limit\n",
903 appl_id, user_id);
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +0000904 err = -EAGAIN;
905 } else
906 err = -EPIPE;
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000907 skb_unlink(skb, &iucv->send_skb_q);
Hendrik Bruecknerbb664f42009-06-17 21:54:47 +0000908 goto fail;
Jennifer Hunteac37312007-02-08 13:51:54 -0800909 }
910
911 release_sock(sk);
912 return len;
913
914fail:
915 kfree_skb(skb);
916out:
917 release_sock(sk);
918 return err;
919}
920
Ursula Braunf0703c82007-10-08 02:03:31 -0700921static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len)
922{
923 int dataleft, size, copied = 0;
924 struct sk_buff *nskb;
925
926 dataleft = len;
927 while (dataleft) {
928 if (dataleft >= sk->sk_rcvbuf / 4)
929 size = sk->sk_rcvbuf / 4;
930 else
931 size = dataleft;
932
933 nskb = alloc_skb(size, GFP_ATOMIC | GFP_DMA);
934 if (!nskb)
935 return -ENOMEM;
936
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +0000937 /* copy target class to control buffer of new skb */
938 memcpy(CB_TRGCLS(nskb), CB_TRGCLS(skb), CB_TRGCLS_LEN);
939
940 /* copy data fragment */
Ursula Braunf0703c82007-10-08 02:03:31 -0700941 memcpy(nskb->data, skb->data + copied, size);
942 copied += size;
943 dataleft -= size;
944
945 skb_reset_transport_header(nskb);
946 skb_reset_network_header(nskb);
947 nskb->len = size;
948
949 skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, nskb);
950 }
951
952 return 0;
953}
954
955static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
956 struct iucv_path *path,
957 struct iucv_message *msg)
958{
959 int rc;
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000960 unsigned int len;
Ursula Braunf0703c82007-10-08 02:03:31 -0700961
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000962 len = iucv_msg_length(msg);
963
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +0000964 /* store msg target class in the second 4 bytes of skb ctrl buffer */
965 /* Note: the first 4 bytes are reserved for msg tag */
966 memcpy(CB_TRGCLS(skb), &msg->class, CB_TRGCLS_LEN);
967
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000968 /* check for special IPRM messages (e.g. iucv_sock_shutdown) */
969 if ((msg->flags & IUCV_IPRMDATA) && len > 7) {
970 if (memcmp(msg->rmmsg, iprm_shutdown, 8) == 0) {
971 skb->data = NULL;
972 skb->len = 0;
973 }
Ursula Braunf0703c82007-10-08 02:03:31 -0700974 } else {
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000975 rc = iucv_message_receive(path, msg, msg->flags & IUCV_IPRMDATA,
976 skb->data, len, NULL);
Ursula Braunf0703c82007-10-08 02:03:31 -0700977 if (rc) {
978 kfree_skb(skb);
979 return;
980 }
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +0000981 /* we need to fragment iucv messages for SOCK_STREAM only;
982 * for SOCK_SEQPACKET, it is only relevant if we support
983 * record segmentation using MSG_EOR (see also recvmsg()) */
984 if (sk->sk_type == SOCK_STREAM &&
985 skb->truesize >= sk->sk_rcvbuf / 4) {
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000986 rc = iucv_fragment_skb(sk, skb, len);
Ursula Braunf0703c82007-10-08 02:03:31 -0700987 kfree_skb(skb);
988 skb = NULL;
989 if (rc) {
990 iucv_path_sever(path, NULL);
991 return;
992 }
993 skb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q);
994 } else {
995 skb_reset_transport_header(skb);
996 skb_reset_network_header(skb);
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +0000997 skb->len = len;
Ursula Braunf0703c82007-10-08 02:03:31 -0700998 }
999 }
1000
1001 if (sock_queue_rcv_skb(sk, skb))
1002 skb_queue_head(&iucv_sk(sk)->backlog_skb_q, skb);
1003}
1004
1005static void iucv_process_message_q(struct sock *sk)
1006{
1007 struct iucv_sock *iucv = iucv_sk(sk);
1008 struct sk_buff *skb;
1009 struct sock_msg_q *p, *n;
1010
1011 list_for_each_entry_safe(p, n, &iucv->message_q.list, list) {
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +00001012 skb = alloc_skb(iucv_msg_length(&p->msg), GFP_ATOMIC | GFP_DMA);
Ursula Braunf0703c82007-10-08 02:03:31 -07001013 if (!skb)
1014 break;
1015 iucv_process_message(sk, skb, p->path, &p->msg);
1016 list_del(&p->list);
1017 kfree(p);
1018 if (!skb_queue_empty(&iucv->backlog_skb_q))
1019 break;
1020 }
1021}
1022
Jennifer Hunteac37312007-02-08 13:51:54 -08001023static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
1024 struct msghdr *msg, size_t len, int flags)
1025{
1026 int noblock = flags & MSG_DONTWAIT;
1027 struct sock *sk = sock->sk;
Jennifer Hunt561e0362007-05-04 12:22:07 -07001028 struct iucv_sock *iucv = iucv_sk(sk);
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +00001029 unsigned int copied, rlen;
Jennifer Hunt561e0362007-05-04 12:22:07 -07001030 struct sk_buff *skb, *rskb, *cskb;
Jennifer Hunteac37312007-02-08 13:51:54 -08001031 int err = 0;
1032
Jennifer Hunt561e0362007-05-04 12:22:07 -07001033 if ((sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED) &&
Ursula Braunf0703c82007-10-08 02:03:31 -07001034 skb_queue_empty(&iucv->backlog_skb_q) &&
1035 skb_queue_empty(&sk->sk_receive_queue) &&
1036 list_empty(&iucv->message_q.list))
Jennifer Hunt561e0362007-05-04 12:22:07 -07001037 return 0;
1038
Jennifer Hunteac37312007-02-08 13:51:54 -08001039 if (flags & (MSG_OOB))
1040 return -EOPNOTSUPP;
1041
Hendrik Brueckner60d37052009-04-21 06:04:21 +00001042 /* receive/dequeue next skb:
1043 * the function understands MSG_PEEK and, thus, does not dequeue skb */
Jennifer Hunteac37312007-02-08 13:51:54 -08001044 skb = skb_recv_datagram(sk, flags, noblock, &err);
1045 if (!skb) {
1046 if (sk->sk_shutdown & RCV_SHUTDOWN)
1047 return 0;
1048 return err;
1049 }
1050
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +00001051 rlen = skb->len; /* real length of skb */
1052 copied = min_t(unsigned int, rlen, len);
Jennifer Hunteac37312007-02-08 13:51:54 -08001053
Jennifer Hunt561e0362007-05-04 12:22:07 -07001054 cskb = skb;
1055 if (memcpy_toiovec(msg->msg_iov, cskb->data, copied)) {
Hendrik Brueckner802788b2009-04-21 23:26:26 +00001056 if (!(flags & MSG_PEEK))
1057 skb_queue_head(&sk->sk_receive_queue, skb);
1058 return -EFAULT;
Jennifer Hunteac37312007-02-08 13:51:54 -08001059 }
1060
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +00001061 /* SOCK_SEQPACKET: set MSG_TRUNC if recv buf size is too small */
1062 if (sk->sk_type == SOCK_SEQPACKET) {
1063 if (copied < rlen)
1064 msg->msg_flags |= MSG_TRUNC;
1065 /* each iucv message contains a complete record */
1066 msg->msg_flags |= MSG_EOR;
1067 }
Jennifer Hunteac37312007-02-08 13:51:54 -08001068
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +00001069 /* create control message to store iucv msg target class:
1070 * get the trgcls from the control buffer of the skb due to
1071 * fragmentation of original iucv message. */
1072 err = put_cmsg(msg, SOL_IUCV, SCM_IUCV_TRGCLS,
1073 CB_TRGCLS_LEN, CB_TRGCLS(skb));
1074 if (err) {
1075 if (!(flags & MSG_PEEK))
1076 skb_queue_head(&sk->sk_receive_queue, skb);
1077 return err;
1078 }
1079
Jennifer Hunteac37312007-02-08 13:51:54 -08001080 /* Mark read part of skb as used */
1081 if (!(flags & MSG_PEEK)) {
Jennifer Hunteac37312007-02-08 13:51:54 -08001082
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +00001083 /* SOCK_STREAM: re-queue skb if it contains unreceived data */
1084 if (sk->sk_type == SOCK_STREAM) {
1085 skb_pull(skb, copied);
1086 if (skb->len) {
1087 skb_queue_head(&sk->sk_receive_queue, skb);
1088 goto done;
1089 }
Jennifer Hunteac37312007-02-08 13:51:54 -08001090 }
1091
1092 kfree_skb(skb);
Jennifer Hunt561e0362007-05-04 12:22:07 -07001093
1094 /* Queue backlog skbs */
Ursula Braunf0703c82007-10-08 02:03:31 -07001095 rskb = skb_dequeue(&iucv->backlog_skb_q);
Heiko Carstensda99f052007-05-04 12:23:27 -07001096 while (rskb) {
Jennifer Hunt561e0362007-05-04 12:22:07 -07001097 if (sock_queue_rcv_skb(sk, rskb)) {
Ursula Braunf0703c82007-10-08 02:03:31 -07001098 skb_queue_head(&iucv->backlog_skb_q,
Jennifer Hunt561e0362007-05-04 12:22:07 -07001099 rskb);
1100 break;
1101 } else {
Ursula Braunf0703c82007-10-08 02:03:31 -07001102 rskb = skb_dequeue(&iucv->backlog_skb_q);
Jennifer Hunt561e0362007-05-04 12:22:07 -07001103 }
1104 }
Ursula Braunf0703c82007-10-08 02:03:31 -07001105 if (skb_queue_empty(&iucv->backlog_skb_q)) {
1106 spin_lock_bh(&iucv->message_q.lock);
1107 if (!list_empty(&iucv->message_q.list))
1108 iucv_process_message_q(sk);
1109 spin_unlock_bh(&iucv->message_q.lock);
1110 }
Hendrik Brueckner60d37052009-04-21 06:04:21 +00001111 }
Jennifer Hunteac37312007-02-08 13:51:54 -08001112
1113done:
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +00001114 /* SOCK_SEQPACKET: return real length if MSG_TRUNC is set */
1115 if (sk->sk_type == SOCK_SEQPACKET && (flags & MSG_TRUNC))
1116 copied = rlen;
1117
1118 return copied;
Jennifer Hunteac37312007-02-08 13:51:54 -08001119}
1120
1121static inline unsigned int iucv_accept_poll(struct sock *parent)
1122{
1123 struct iucv_sock *isk, *n;
1124 struct sock *sk;
1125
Heiko Carstensda99f052007-05-04 12:23:27 -07001126 list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q) {
Jennifer Hunteac37312007-02-08 13:51:54 -08001127 sk = (struct sock *) isk;
1128
1129 if (sk->sk_state == IUCV_CONNECTED)
1130 return POLLIN | POLLRDNORM;
1131 }
1132
1133 return 0;
1134}
1135
1136unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
1137 poll_table *wait)
1138{
1139 struct sock *sk = sock->sk;
1140 unsigned int mask = 0;
1141
1142 poll_wait(file, sk->sk_sleep, wait);
1143
1144 if (sk->sk_state == IUCV_LISTEN)
1145 return iucv_accept_poll(sk);
1146
1147 if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
1148 mask |= POLLERR;
1149
1150 if (sk->sk_shutdown & RCV_SHUTDOWN)
1151 mask |= POLLRDHUP;
1152
1153 if (sk->sk_shutdown == SHUTDOWN_MASK)
1154 mask |= POLLHUP;
1155
1156 if (!skb_queue_empty(&sk->sk_receive_queue) ||
Heiko Carstensda99f052007-05-04 12:23:27 -07001157 (sk->sk_shutdown & RCV_SHUTDOWN))
Jennifer Hunteac37312007-02-08 13:51:54 -08001158 mask |= POLLIN | POLLRDNORM;
1159
1160 if (sk->sk_state == IUCV_CLOSED)
1161 mask |= POLLHUP;
1162
Jennifer Hunt561e0362007-05-04 12:22:07 -07001163 if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED)
1164 mask |= POLLIN;
1165
Jennifer Hunteac37312007-02-08 13:51:54 -08001166 if (sock_writeable(sk))
1167 mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
1168 else
1169 set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
1170
1171 return mask;
1172}
1173
1174static int iucv_sock_shutdown(struct socket *sock, int how)
1175{
1176 struct sock *sk = sock->sk;
1177 struct iucv_sock *iucv = iucv_sk(sk);
1178 struct iucv_message txmsg;
1179 int err = 0;
Jennifer Hunteac37312007-02-08 13:51:54 -08001180
1181 how++;
1182
1183 if ((how & ~SHUTDOWN_MASK) || !how)
1184 return -EINVAL;
1185
1186 lock_sock(sk);
Heiko Carstensda99f052007-05-04 12:23:27 -07001187 switch (sk->sk_state) {
Hendrik Bruecknere14ad5f2009-04-21 06:04:23 +00001188 case IUCV_DISCONN:
1189 case IUCV_CLOSING:
1190 case IUCV_SEVERED:
Jennifer Hunteac37312007-02-08 13:51:54 -08001191 case IUCV_CLOSED:
1192 err = -ENOTCONN;
1193 goto fail;
1194
1195 default:
1196 sk->sk_shutdown |= how;
1197 break;
1198 }
1199
1200 if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
1201 txmsg.class = 0;
1202 txmsg.tag = 0;
1203 err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0,
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +00001204 (void *) iprm_shutdown, 8);
Jennifer Hunteac37312007-02-08 13:51:54 -08001205 if (err) {
Heiko Carstensda99f052007-05-04 12:23:27 -07001206 switch (err) {
Jennifer Hunteac37312007-02-08 13:51:54 -08001207 case 1:
1208 err = -ENOTCONN;
1209 break;
1210 case 2:
1211 err = -ECONNRESET;
1212 break;
1213 default:
1214 err = -ENOTCONN;
1215 break;
1216 }
1217 }
1218 }
1219
1220 if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
1221 err = iucv_path_quiesce(iucv_sk(sk)->path, NULL);
1222 if (err)
1223 err = -ENOTCONN;
1224
1225 skb_queue_purge(&sk->sk_receive_queue);
1226 }
1227
1228 /* Wake up anyone sleeping in poll */
1229 sk->sk_state_change(sk);
1230
1231fail:
1232 release_sock(sk);
1233 return err;
1234}
1235
1236static int iucv_sock_release(struct socket *sock)
1237{
1238 struct sock *sk = sock->sk;
1239 int err = 0;
1240
1241 if (!sk)
1242 return 0;
1243
1244 iucv_sock_close(sk);
1245
1246 /* Unregister with IUCV base support */
1247 if (iucv_sk(sk)->path) {
1248 iucv_path_sever(iucv_sk(sk)->path, NULL);
1249 iucv_path_free(iucv_sk(sk)->path);
1250 iucv_sk(sk)->path = NULL;
1251 }
1252
Jennifer Hunteac37312007-02-08 13:51:54 -08001253 sock_orphan(sk);
1254 iucv_sock_kill(sk);
1255 return err;
1256}
1257
Hendrik Brueckner9d5c5d82009-04-21 23:26:22 +00001258/* getsockopt and setsockopt */
1259static int iucv_sock_setsockopt(struct socket *sock, int level, int optname,
1260 char __user *optval, int optlen)
1261{
1262 struct sock *sk = sock->sk;
1263 struct iucv_sock *iucv = iucv_sk(sk);
1264 int val;
1265 int rc;
1266
1267 if (level != SOL_IUCV)
1268 return -ENOPROTOOPT;
1269
1270 if (optlen < sizeof(int))
1271 return -EINVAL;
1272
1273 if (get_user(val, (int __user *) optval))
1274 return -EFAULT;
1275
1276 rc = 0;
1277
1278 lock_sock(sk);
1279 switch (optname) {
1280 case SO_IPRMDATA_MSG:
1281 if (val)
1282 iucv->flags |= IUCV_IPRMDATA;
1283 else
1284 iucv->flags &= ~IUCV_IPRMDATA;
1285 break;
Hendrik Brueckner09488e2e2009-04-21 23:26:27 +00001286 case SO_MSGLIMIT:
1287 switch (sk->sk_state) {
1288 case IUCV_OPEN:
1289 case IUCV_BOUND:
1290 if (val < 1 || val > (u16)(~0))
1291 rc = -EINVAL;
1292 else
1293 iucv->msglimit = val;
1294 break;
1295 default:
1296 rc = -EINVAL;
1297 break;
1298 }
1299 break;
Hendrik Brueckner9d5c5d82009-04-21 23:26:22 +00001300 default:
1301 rc = -ENOPROTOOPT;
1302 break;
1303 }
1304 release_sock(sk);
1305
1306 return rc;
1307}
1308
1309static int iucv_sock_getsockopt(struct socket *sock, int level, int optname,
1310 char __user *optval, int __user *optlen)
1311{
1312 struct sock *sk = sock->sk;
1313 struct iucv_sock *iucv = iucv_sk(sk);
1314 int val, len;
1315
1316 if (level != SOL_IUCV)
1317 return -ENOPROTOOPT;
1318
1319 if (get_user(len, optlen))
1320 return -EFAULT;
1321
1322 if (len < 0)
1323 return -EINVAL;
1324
1325 len = min_t(unsigned int, len, sizeof(int));
1326
1327 switch (optname) {
1328 case SO_IPRMDATA_MSG:
1329 val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0;
1330 break;
Hendrik Brueckner09488e2e2009-04-21 23:26:27 +00001331 case SO_MSGLIMIT:
1332 lock_sock(sk);
1333 val = (iucv->path != NULL) ? iucv->path->msglim /* connected */
1334 : iucv->msglimit; /* default */
1335 release_sock(sk);
1336 break;
Hendrik Brueckner9d5c5d82009-04-21 23:26:22 +00001337 default:
1338 return -ENOPROTOOPT;
1339 }
1340
1341 if (put_user(len, optlen))
1342 return -EFAULT;
1343 if (copy_to_user(optval, &val, len))
1344 return -EFAULT;
1345
1346 return 0;
1347}
1348
1349
Jennifer Hunteac37312007-02-08 13:51:54 -08001350/* Callback wrappers - called from iucv base support */
1351static int iucv_callback_connreq(struct iucv_path *path,
1352 u8 ipvmid[8], u8 ipuser[16])
1353{
1354 unsigned char user_data[16];
1355 unsigned char nuser_data[16];
1356 unsigned char src_name[8];
1357 struct hlist_node *node;
1358 struct sock *sk, *nsk;
1359 struct iucv_sock *iucv, *niucv;
1360 int err;
1361
1362 memcpy(src_name, ipuser, 8);
1363 EBCASC(src_name, 8);
1364 /* Find out if this path belongs to af_iucv. */
1365 read_lock(&iucv_sk_list.lock);
1366 iucv = NULL;
Ursula Braunfebca282007-07-14 19:04:25 -07001367 sk = NULL;
Jennifer Hunteac37312007-02-08 13:51:54 -08001368 sk_for_each(sk, node, &iucv_sk_list.head)
1369 if (sk->sk_state == IUCV_LISTEN &&
1370 !memcmp(&iucv_sk(sk)->src_name, src_name, 8)) {
1371 /*
1372 * Found a listening socket with
1373 * src_name == ipuser[0-7].
1374 */
1375 iucv = iucv_sk(sk);
1376 break;
1377 }
1378 read_unlock(&iucv_sk_list.lock);
1379 if (!iucv)
1380 /* No socket found, not one of our paths. */
1381 return -EINVAL;
1382
1383 bh_lock_sock(sk);
1384
1385 /* Check if parent socket is listening */
1386 low_nmcpy(user_data, iucv->src_name);
1387 high_nmcpy(user_data, iucv->dst_name);
1388 ASCEBC(user_data, sizeof(user_data));
1389 if (sk->sk_state != IUCV_LISTEN) {
1390 err = iucv_path_sever(path, user_data);
Hendrik Brueckner65dbd7c2009-01-05 18:08:23 -08001391 iucv_path_free(path);
Jennifer Hunteac37312007-02-08 13:51:54 -08001392 goto fail;
1393 }
1394
1395 /* Check for backlog size */
1396 if (sk_acceptq_is_full(sk)) {
1397 err = iucv_path_sever(path, user_data);
Hendrik Brueckner65dbd7c2009-01-05 18:08:23 -08001398 iucv_path_free(path);
Jennifer Hunteac37312007-02-08 13:51:54 -08001399 goto fail;
1400 }
1401
1402 /* Create the new socket */
Hendrik Brueckneraa8e71f2009-04-21 23:26:25 +00001403 nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC);
Heiko Carstensda99f052007-05-04 12:23:27 -07001404 if (!nsk) {
Jennifer Hunteac37312007-02-08 13:51:54 -08001405 err = iucv_path_sever(path, user_data);
Hendrik Brueckner65dbd7c2009-01-05 18:08:23 -08001406 iucv_path_free(path);
Jennifer Hunteac37312007-02-08 13:51:54 -08001407 goto fail;
1408 }
1409
1410 niucv = iucv_sk(nsk);
1411 iucv_sock_init(nsk, sk);
1412
1413 /* Set the new iucv_sock */
1414 memcpy(niucv->dst_name, ipuser + 8, 8);
1415 EBCASC(niucv->dst_name, 8);
1416 memcpy(niucv->dst_user_id, ipvmid, 8);
1417 memcpy(niucv->src_name, iucv->src_name, 8);
1418 memcpy(niucv->src_user_id, iucv->src_user_id, 8);
1419 niucv->path = path;
1420
1421 /* Call iucv_accept */
1422 high_nmcpy(nuser_data, ipuser + 8);
1423 memcpy(nuser_data + 8, niucv->src_name, 8);
1424 ASCEBC(nuser_data + 8, 8);
1425
Hendrik Brueckner09488e2e2009-04-21 23:26:27 +00001426 /* set message limit for path based on msglimit of accepting socket */
1427 niucv->msglimit = iucv->msglimit;
1428 path->msglim = iucv->msglimit;
Jennifer Hunteac37312007-02-08 13:51:54 -08001429 err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk);
Heiko Carstensda99f052007-05-04 12:23:27 -07001430 if (err) {
Jennifer Hunteac37312007-02-08 13:51:54 -08001431 err = iucv_path_sever(path, user_data);
Hendrik Brueckner65dbd7c2009-01-05 18:08:23 -08001432 iucv_path_free(path);
1433 iucv_sock_kill(nsk);
Jennifer Hunteac37312007-02-08 13:51:54 -08001434 goto fail;
1435 }
1436
1437 iucv_accept_enqueue(sk, nsk);
1438
1439 /* Wake up accept */
1440 nsk->sk_state = IUCV_CONNECTED;
1441 sk->sk_data_ready(sk, 1);
1442 err = 0;
1443fail:
1444 bh_unlock_sock(sk);
1445 return 0;
1446}
1447
1448static void iucv_callback_connack(struct iucv_path *path, u8 ipuser[16])
1449{
1450 struct sock *sk = path->private;
1451
1452 sk->sk_state = IUCV_CONNECTED;
1453 sk->sk_state_change(sk);
1454}
1455
1456static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
1457{
1458 struct sock *sk = path->private;
Jennifer Hunt561e0362007-05-04 12:22:07 -07001459 struct iucv_sock *iucv = iucv_sk(sk);
Ursula Braunf0703c82007-10-08 02:03:31 -07001460 struct sk_buff *skb;
1461 struct sock_msg_q *save_msg;
1462 int len;
Jennifer Hunt561e0362007-05-04 12:22:07 -07001463
Hendrik Bruecknerfe86e542009-04-21 06:04:22 +00001464 if (sk->sk_shutdown & RCV_SHUTDOWN) {
1465 iucv_message_reject(path, msg);
Jennifer Hunteac37312007-02-08 13:51:54 -08001466 return;
Hendrik Bruecknerfe86e542009-04-21 06:04:22 +00001467 }
Jennifer Hunteac37312007-02-08 13:51:54 -08001468
Hendrik Brueckner3fa6b5a2009-04-21 06:04:24 +00001469 spin_lock(&iucv->message_q.lock);
Jennifer Hunteac37312007-02-08 13:51:54 -08001470
Ursula Braunf0703c82007-10-08 02:03:31 -07001471 if (!list_empty(&iucv->message_q.list) ||
1472 !skb_queue_empty(&iucv->backlog_skb_q))
1473 goto save_message;
1474
1475 len = atomic_read(&sk->sk_rmem_alloc);
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +00001476 len += iucv_msg_length(msg) + sizeof(struct sk_buff);
Ursula Braunf0703c82007-10-08 02:03:31 -07001477 if (len > sk->sk_rcvbuf)
1478 goto save_message;
1479
Hendrik Bruecknerb8942e32009-04-21 23:26:23 +00001480 skb = alloc_skb(iucv_msg_length(msg), GFP_ATOMIC | GFP_DMA);
Ursula Braunf0703c82007-10-08 02:03:31 -07001481 if (!skb)
1482 goto save_message;
Jennifer Hunteac37312007-02-08 13:51:54 -08001483
Ursula Braunf0703c82007-10-08 02:03:31 -07001484 iucv_process_message(sk, skb, path, msg);
Hendrik Brueckner3fa6b5a2009-04-21 06:04:24 +00001485 goto out_unlock;
Jennifer Hunteac37312007-02-08 13:51:54 -08001486
Ursula Braunf0703c82007-10-08 02:03:31 -07001487save_message:
1488 save_msg = kzalloc(sizeof(struct sock_msg_q), GFP_ATOMIC | GFP_DMA);
Ursula Braund4444722008-02-07 18:07:19 -08001489 if (!save_msg)
1490 return;
Ursula Braunf0703c82007-10-08 02:03:31 -07001491 save_msg->path = path;
1492 save_msg->msg = *msg;
1493
Ursula Braunf0703c82007-10-08 02:03:31 -07001494 list_add_tail(&save_msg->list, &iucv->message_q.list);
Hendrik Brueckner3fa6b5a2009-04-21 06:04:24 +00001495
1496out_unlock:
Ursula Braunf0703c82007-10-08 02:03:31 -07001497 spin_unlock(&iucv->message_q.lock);
Jennifer Hunteac37312007-02-08 13:51:54 -08001498}
1499
1500static void iucv_callback_txdone(struct iucv_path *path,
1501 struct iucv_message *msg)
1502{
1503 struct sock *sk = path->private;
Ursula Braunf2a77992008-02-07 18:07:44 -08001504 struct sk_buff *this = NULL;
Jennifer Hunteac37312007-02-08 13:51:54 -08001505 struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q;
1506 struct sk_buff *list_skb = list->next;
1507 unsigned long flags;
1508
Ursula Braunf2a77992008-02-07 18:07:44 -08001509 if (!skb_queue_empty(list)) {
Jennifer Hunt561e0362007-05-04 12:22:07 -07001510 spin_lock_irqsave(&list->lock, flags);
Jennifer Hunteac37312007-02-08 13:51:54 -08001511
Ursula Braunf2a77992008-02-07 18:07:44 -08001512 while (list_skb != (struct sk_buff *)list) {
Hendrik Brueckner44b1e6b2009-04-21 23:26:24 +00001513 if (!memcmp(&msg->tag, CB_TAG(list_skb), CB_TAG_LEN)) {
Ursula Braunf2a77992008-02-07 18:07:44 -08001514 this = list_skb;
1515 break;
1516 }
Jennifer Hunt561e0362007-05-04 12:22:07 -07001517 list_skb = list_skb->next;
Ursula Braunf2a77992008-02-07 18:07:44 -08001518 }
1519 if (this)
1520 __skb_unlink(this, list);
Jennifer Hunteac37312007-02-08 13:51:54 -08001521
Jennifer Hunt561e0362007-05-04 12:22:07 -07001522 spin_unlock_irqrestore(&list->lock, flags);
Jennifer Hunteac37312007-02-08 13:51:54 -08001523
Hendrik Brueckner0ea920d2009-06-17 21:54:48 +00001524 if (this) {
1525 kfree_skb(this);
1526 /* wake up any process waiting for sending */
1527 iucv_sock_wake_msglim(sk);
1528 }
Jennifer Hunt561e0362007-05-04 12:22:07 -07001529 }
Ursula Braunc2b4afd2008-07-14 09:59:29 +02001530 BUG_ON(!this);
Jennifer Hunt561e0362007-05-04 12:22:07 -07001531
Heiko Carstensda99f052007-05-04 12:23:27 -07001532 if (sk->sk_state == IUCV_CLOSING) {
Jennifer Hunt561e0362007-05-04 12:22:07 -07001533 if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) {
1534 sk->sk_state = IUCV_CLOSED;
1535 sk->sk_state_change(sk);
1536 }
1537 }
1538
Jennifer Hunteac37312007-02-08 13:51:54 -08001539}
1540
1541static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
1542{
1543 struct sock *sk = path->private;
1544
1545 if (!list_empty(&iucv_sk(sk)->accept_q))
1546 sk->sk_state = IUCV_SEVERED;
1547 else
1548 sk->sk_state = IUCV_DISCONN;
1549
1550 sk->sk_state_change(sk);
1551}
1552
Hendrik Brueckneraf88b522009-04-21 23:26:21 +00001553/* called if the other communication side shuts down its RECV direction;
1554 * in turn, the callback sets SEND_SHUTDOWN to disable sending of data.
1555 */
1556static void iucv_callback_shutdown(struct iucv_path *path, u8 ipuser[16])
1557{
1558 struct sock *sk = path->private;
1559
1560 bh_lock_sock(sk);
1561 if (sk->sk_state != IUCV_CLOSED) {
1562 sk->sk_shutdown |= SEND_SHUTDOWN;
1563 sk->sk_state_change(sk);
1564 }
1565 bh_unlock_sock(sk);
1566}
1567
Jennifer Hunteac37312007-02-08 13:51:54 -08001568static struct proto_ops iucv_sock_ops = {
1569 .family = PF_IUCV,
1570 .owner = THIS_MODULE,
1571 .release = iucv_sock_release,
1572 .bind = iucv_sock_bind,
1573 .connect = iucv_sock_connect,
1574 .listen = iucv_sock_listen,
1575 .accept = iucv_sock_accept,
1576 .getname = iucv_sock_getname,
1577 .sendmsg = iucv_sock_sendmsg,
1578 .recvmsg = iucv_sock_recvmsg,
1579 .poll = iucv_sock_poll,
1580 .ioctl = sock_no_ioctl,
1581 .mmap = sock_no_mmap,
1582 .socketpair = sock_no_socketpair,
1583 .shutdown = iucv_sock_shutdown,
Hendrik Brueckner9d5c5d82009-04-21 23:26:22 +00001584 .setsockopt = iucv_sock_setsockopt,
1585 .getsockopt = iucv_sock_getsockopt,
Jennifer Hunteac37312007-02-08 13:51:54 -08001586};
1587
1588static struct net_proto_family iucv_sock_family_ops = {
1589 .family = AF_IUCV,
1590 .owner = THIS_MODULE,
1591 .create = iucv_sock_create,
1592};
1593
Heiko Carstensda99f052007-05-04 12:23:27 -07001594static int __init afiucv_init(void)
Jennifer Hunteac37312007-02-08 13:51:54 -08001595{
1596 int err;
1597
1598 if (!MACHINE_IS_VM) {
Ursula Braun8f7c5022008-12-25 13:39:47 +01001599 pr_err("The af_iucv module cannot be loaded"
1600 " without z/VM\n");
Jennifer Hunteac37312007-02-08 13:51:54 -08001601 err = -EPROTONOSUPPORT;
1602 goto out;
1603 }
1604 cpcmd("QUERY USERID", iucv_userid, sizeof(iucv_userid), &err);
1605 if (unlikely(err)) {
Ursula Braunc2b4afd2008-07-14 09:59:29 +02001606 WARN_ON(err);
Jennifer Hunteac37312007-02-08 13:51:54 -08001607 err = -EPROTONOSUPPORT;
1608 goto out;
1609 }
1610
1611 err = iucv_register(&af_iucv_handler, 0);
1612 if (err)
1613 goto out;
1614 err = proto_register(&iucv_proto, 0);
1615 if (err)
1616 goto out_iucv;
1617 err = sock_register(&iucv_sock_family_ops);
1618 if (err)
1619 goto out_proto;
Jennifer Hunteac37312007-02-08 13:51:54 -08001620 return 0;
1621
1622out_proto:
1623 proto_unregister(&iucv_proto);
1624out_iucv:
1625 iucv_unregister(&af_iucv_handler, 0);
1626out:
1627 return err;
1628}
1629
1630static void __exit afiucv_exit(void)
1631{
1632 sock_unregister(PF_IUCV);
1633 proto_unregister(&iucv_proto);
1634 iucv_unregister(&af_iucv_handler, 0);
Jennifer Hunteac37312007-02-08 13:51:54 -08001635}
1636
1637module_init(afiucv_init);
1638module_exit(afiucv_exit);
1639
1640MODULE_AUTHOR("Jennifer Hunt <jenhunt@us.ibm.com>");
1641MODULE_DESCRIPTION("IUCV Sockets ver " VERSION);
1642MODULE_VERSION(VERSION);
1643MODULE_LICENSE("GPL");
1644MODULE_ALIAS_NETPROTO(PF_IUCV);