aboutsummaryrefslogtreecommitdiffstats
path: root/net/iucv/af_iucv.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/iucv/af_iucv.c')
-rw-r--r--net/iucv/af_iucv.c106
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 */
457static 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 */
457static void iucv_sock_close(struct sock *sk) 473static 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
785static 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);
801done:
802 return err;
803}
804
805static int afiucv_path_connect(struct socket *sock, struct sockaddr *addr) 792static 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 */
2274static 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
2304static struct notifier_block afiucv_netdev_notifier = {
2305 .notifier_call = afiucv_netdev_event,
2306};
2307
2292static const struct proto_ops iucv_sock_ops = { 2308static 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);