diff options
Diffstat (limited to 'net/iucv/af_iucv.c')
-rw-r--r-- | net/iucv/af_iucv.c | 106 |
1 files changed, 62 insertions, 44 deletions
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 98d1f0ba7fe9..31537c5eb17e 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c | |||
@@ -453,14 +453,28 @@ static void iucv_sever_path(struct sock *sk, int with_user_data) | |||
453 | } | 453 | } |
454 | } | 454 | } |
455 | 455 | ||
456 | /* Send FIN through an IUCV socket for HIPER transport */ | ||
457 | static int iucv_send_ctrl(struct sock *sk, u8 flags) | ||
458 | { | ||
459 | int err = 0; | ||
460 | int blen; | ||
461 | struct sk_buff *skb; | ||
462 | |||
463 | blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN; | ||
464 | skb = sock_alloc_send_skb(sk, blen, 1, &err); | ||
465 | if (skb) { | ||
466 | skb_reserve(skb, blen); | ||
467 | err = afiucv_hs_send(NULL, sk, skb, flags); | ||
468 | } | ||
469 | return err; | ||
470 | } | ||
471 | |||
456 | /* Close an IUCV socket */ | 472 | /* Close an IUCV socket */ |
457 | static void iucv_sock_close(struct sock *sk) | 473 | static void iucv_sock_close(struct sock *sk) |
458 | { | 474 | { |
459 | struct iucv_sock *iucv = iucv_sk(sk); | 475 | struct iucv_sock *iucv = iucv_sk(sk); |
460 | unsigned long timeo; | 476 | unsigned long timeo; |
461 | int err = 0; | 477 | int err = 0; |
462 | int blen; | ||
463 | struct sk_buff *skb; | ||
464 | 478 | ||
465 | lock_sock(sk); | 479 | lock_sock(sk); |
466 | 480 | ||
@@ -471,14 +485,7 @@ static void iucv_sock_close(struct sock *sk) | |||
471 | 485 | ||
472 | case IUCV_CONNECTED: | 486 | case IUCV_CONNECTED: |
473 | if (iucv->transport == AF_IUCV_TRANS_HIPER) { | 487 | if (iucv->transport == AF_IUCV_TRANS_HIPER) { |
474 | /* send fin */ | 488 | err = iucv_send_ctrl(sk, AF_IUCV_FLAG_FIN); |
475 | blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN; | ||
476 | skb = sock_alloc_send_skb(sk, blen, 1, &err); | ||
477 | if (skb) { | ||
478 | skb_reserve(skb, blen); | ||
479 | err = afiucv_hs_send(NULL, sk, skb, | ||
480 | AF_IUCV_FLAG_FIN); | ||
481 | } | ||
482 | sk->sk_state = IUCV_DISCONN; | 489 | sk->sk_state = IUCV_DISCONN; |
483 | sk->sk_state_change(sk); | 490 | sk->sk_state_change(sk); |
484 | } | 491 | } |
@@ -782,26 +789,6 @@ static int iucv_sock_autobind(struct sock *sk) | |||
782 | return err; | 789 | return err; |
783 | } | 790 | } |
784 | 791 | ||
785 | static int afiucv_hs_connect(struct socket *sock) | ||
786 | { | ||
787 | struct sock *sk = sock->sk; | ||
788 | struct sk_buff *skb; | ||
789 | int blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN; | ||
790 | int err = 0; | ||
791 | |||
792 | /* send syn */ | ||
793 | skb = sock_alloc_send_skb(sk, blen, 1, &err); | ||
794 | if (!skb) { | ||
795 | err = -ENOMEM; | ||
796 | goto done; | ||
797 | } | ||
798 | skb->dev = NULL; | ||
799 | skb_reserve(skb, blen); | ||
800 | err = afiucv_hs_send(NULL, sk, skb, AF_IUCV_FLAG_SYN); | ||
801 | done: | ||
802 | return err; | ||
803 | } | ||
804 | |||
805 | static int afiucv_path_connect(struct socket *sock, struct sockaddr *addr) | 792 | static int afiucv_path_connect(struct socket *sock, struct sockaddr *addr) |
806 | { | 793 | { |
807 | struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr; | 794 | struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr; |
@@ -882,7 +869,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, | |||
882 | memcpy(iucv->dst_name, sa->siucv_name, 8); | 869 | memcpy(iucv->dst_name, sa->siucv_name, 8); |
883 | 870 | ||
884 | if (iucv->transport == AF_IUCV_TRANS_HIPER) | 871 | if (iucv->transport == AF_IUCV_TRANS_HIPER) |
885 | err = afiucv_hs_connect(sock); | 872 | err = iucv_send_ctrl(sock->sk, AF_IUCV_FLAG_SYN); |
886 | else | 873 | else |
887 | err = afiucv_path_connect(sock, addr); | 874 | err = afiucv_path_connect(sock, addr); |
888 | if (err) | 875 | if (err) |
@@ -1332,8 +1319,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1332 | struct sock *sk = sock->sk; | 1319 | struct sock *sk = sock->sk; |
1333 | struct iucv_sock *iucv = iucv_sk(sk); | 1320 | struct iucv_sock *iucv = iucv_sk(sk); |
1334 | unsigned int copied, rlen; | 1321 | unsigned int copied, rlen; |
1335 | struct sk_buff *skb, *rskb, *cskb, *sskb; | 1322 | struct sk_buff *skb, *rskb, *cskb; |
1336 | int blen; | ||
1337 | int err = 0; | 1323 | int err = 0; |
1338 | 1324 | ||
1339 | if ((sk->sk_state == IUCV_DISCONN) && | 1325 | if ((sk->sk_state == IUCV_DISCONN) && |
@@ -1422,15 +1408,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1422 | iucv_process_message_q(sk); | 1408 | iucv_process_message_q(sk); |
1423 | if (atomic_read(&iucv->msg_recv) >= | 1409 | if (atomic_read(&iucv->msg_recv) >= |
1424 | iucv->msglimit / 2) { | 1410 | iucv->msglimit / 2) { |
1425 | /* send WIN to peer */ | 1411 | err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN); |
1426 | blen = sizeof(struct af_iucv_trans_hdr) + | ||
1427 | ETH_HLEN; | ||
1428 | sskb = sock_alloc_send_skb(sk, blen, 1, &err); | ||
1429 | if (sskb) { | ||
1430 | skb_reserve(sskb, blen); | ||
1431 | err = afiucv_hs_send(NULL, sk, sskb, | ||
1432 | AF_IUCV_FLAG_WIN); | ||
1433 | } | ||
1434 | if (err) { | 1412 | if (err) { |
1435 | sk->sk_state = IUCV_DISCONN; | 1413 | sk->sk_state = IUCV_DISCONN; |
1436 | sk->sk_state_change(sk); | 1414 | sk->sk_state_change(sk); |
@@ -2289,6 +2267,44 @@ out_unlock: | |||
2289 | } | 2267 | } |
2290 | 2268 | ||
2291 | } | 2269 | } |
2270 | |||
2271 | /* | ||
2272 | * afiucv_netdev_event: handle netdev notifier chain events | ||
2273 | */ | ||
2274 | static int afiucv_netdev_event(struct notifier_block *this, | ||
2275 | unsigned long event, void *ptr) | ||
2276 | { | ||
2277 | struct net_device *event_dev = (struct net_device *)ptr; | ||
2278 | struct hlist_node *node; | ||
2279 | struct sock *sk; | ||
2280 | struct iucv_sock *iucv; | ||
2281 | |||
2282 | switch (event) { | ||
2283 | case NETDEV_REBOOT: | ||
2284 | case NETDEV_GOING_DOWN: | ||
2285 | sk_for_each(sk, node, &iucv_sk_list.head) { | ||
2286 | iucv = iucv_sk(sk); | ||
2287 | if ((iucv->hs_dev == event_dev) && | ||
2288 | (sk->sk_state == IUCV_CONNECTED)) { | ||
2289 | if (event == NETDEV_GOING_DOWN) | ||
2290 | iucv_send_ctrl(sk, AF_IUCV_FLAG_FIN); | ||
2291 | sk->sk_state = IUCV_DISCONN; | ||
2292 | sk->sk_state_change(sk); | ||
2293 | } | ||
2294 | } | ||
2295 | break; | ||
2296 | case NETDEV_DOWN: | ||
2297 | case NETDEV_UNREGISTER: | ||
2298 | default: | ||
2299 | break; | ||
2300 | } | ||
2301 | return NOTIFY_DONE; | ||
2302 | } | ||
2303 | |||
2304 | static struct notifier_block afiucv_netdev_notifier = { | ||
2305 | .notifier_call = afiucv_netdev_event, | ||
2306 | }; | ||
2307 | |||
2292 | static const struct proto_ops iucv_sock_ops = { | 2308 | static const struct proto_ops iucv_sock_ops = { |
2293 | .family = PF_IUCV, | 2309 | .family = PF_IUCV, |
2294 | .owner = THIS_MODULE, | 2310 | .owner = THIS_MODULE, |
@@ -2388,7 +2404,8 @@ static int __init afiucv_init(void) | |||
2388 | err = afiucv_iucv_init(); | 2404 | err = afiucv_iucv_init(); |
2389 | if (err) | 2405 | if (err) |
2390 | goto out_sock; | 2406 | goto out_sock; |
2391 | } | 2407 | } else |
2408 | register_netdevice_notifier(&afiucv_netdev_notifier); | ||
2392 | dev_add_pack(&iucv_packet_type); | 2409 | dev_add_pack(&iucv_packet_type); |
2393 | return 0; | 2410 | return 0; |
2394 | 2411 | ||
@@ -2409,7 +2426,8 @@ static void __exit afiucv_exit(void) | |||
2409 | driver_unregister(&af_iucv_driver); | 2426 | driver_unregister(&af_iucv_driver); |
2410 | pr_iucv->iucv_unregister(&af_iucv_handler, 0); | 2427 | pr_iucv->iucv_unregister(&af_iucv_handler, 0); |
2411 | symbol_put(iucv_if); | 2428 | symbol_put(iucv_if); |
2412 | } | 2429 | } else |
2430 | unregister_netdevice_notifier(&afiucv_netdev_notifier); | ||
2413 | dev_remove_pack(&iucv_packet_type); | 2431 | dev_remove_pack(&iucv_packet_type); |
2414 | sock_unregister(PF_IUCV); | 2432 | sock_unregister(PF_IUCV); |
2415 | proto_unregister(&iucv_proto); | 2433 | proto_unregister(&iucv_proto); |