]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - net/iucv/af_iucv.c
net/af_iucv: always register net_device notifier
[thirdparty/kernel/stable.git] / net / iucv / af_iucv.c
index 78ea5a739d101751ff4215f8c2d455cb45a2c6c4..09e1694b6d341a5f1cf81e49643f9267ac4033c4 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  IUCV protocol stack for Linux on zSeries
  *
@@ -13,6 +14,7 @@
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/module.h>
+#include <linux/netdevice.h>
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/errno.h>
@@ -346,14 +348,14 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
        if (imsg)
                memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message));
 
-       skb_push(skb, ETH_HLEN);
-       memset(skb->data, 0, ETH_HLEN);
-
        skb->dev = iucv->hs_dev;
        if (!skb->dev) {
                err = -ENODEV;
                goto err_free;
        }
+
+       dev_hard_header(skb, skb->dev, ETH_P_AF_IUCV, NULL, NULL, skb->len);
+
        if (!(skb->dev->flags & IFF_UP) || !netif_carrier_ok(skb->dev)) {
                err = -ENETDOWN;
                goto err_free;
@@ -366,6 +368,8 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
                skb_trim(skb, skb->dev->mtu);
        }
        skb->protocol = cpu_to_be16(ETH_P_AF_IUCV);
+
+       __skb_header_release(skb);
        nskb = skb_clone(skb, GFP_ATOMIC);
        if (!nskb) {
                err = -ENOMEM;
@@ -465,12 +469,14 @@ static void iucv_sever_path(struct sock *sk, int with_user_data)
 /* Send controlling flags through an IUCV socket for HIPER transport */
 static int iucv_send_ctrl(struct sock *sk, u8 flags)
 {
+       struct iucv_sock *iucv = iucv_sk(sk);
        int err = 0;
        int blen;
        struct sk_buff *skb;
        u8 shutdown = 0;
 
-       blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
+       blen = sizeof(struct af_iucv_trans_hdr) +
+              LL_RESERVED_SPACE(iucv->hs_dev);
        if (sk->sk_shutdown & SEND_SHUTDOWN) {
                /* controlling flags should be sent anyway */
                shutdown = sk->sk_shutdown;
@@ -587,7 +593,6 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio,
 
        sk->sk_destruct = iucv_sock_destruct;
        sk->sk_sndtimeo = IUCV_CONN_TIMEOUT;
-       sk->sk_allocation = GFP_DMA;
 
        sock_reset_flag(sk, SOCK_ZAPPED);
 
@@ -781,6 +786,7 @@ vm_bind:
                memcpy(iucv->src_user_id, iucv_userid, 8);
                sk->sk_state = IUCV_BOUND;
                iucv->transport = AF_IUCV_TRANS_IUCV;
+               sk->sk_allocation |= GFP_DMA;
                if (!iucv->msglimit)
                        iucv->msglimit = IUCV_QUEUELEN_DEFAULT;
                goto done_unlock;
@@ -805,6 +811,8 @@ static int iucv_sock_autobind(struct sock *sk)
                return -EPROTO;
 
        memcpy(iucv->src_user_id, iucv_userid, 8);
+       iucv->transport = AF_IUCV_TRANS_IUCV;
+       sk->sk_allocation |= GFP_DMA;
 
        write_lock_bh(&iucv_sk_list.lock);
        __iucv_auto_name(iucv);
@@ -1130,7 +1138,8 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg,
         * segmented records using the MSG_EOR flag), but
         * for SOCK_STREAM we might want to improve it in future */
        if (iucv->transport == AF_IUCV_TRANS_HIPER) {
-               headroom = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
+               headroom = sizeof(struct af_iucv_trans_hdr) +
+                          LL_RESERVED_SPACE(iucv->hs_dev);
                linear = len;
        } else {
                if (len < PAGE_SIZE) {
@@ -1780,6 +1789,8 @@ static int iucv_callback_connreq(struct iucv_path *path,
 
        niucv = iucv_sk(nsk);
        iucv_sock_init(nsk, sk);
+       niucv->transport = AF_IUCV_TRANS_IUCV;
+       nsk->sk_allocation |= GFP_DMA;
 
        /* Set the new iucv_sock */
        memcpy(niucv->dst_name, ipuser + 8, 8);
@@ -2429,6 +2440,13 @@ out:
        return err;
 }
 
+static void afiucv_iucv_exit(void)
+{
+       device_unregister(af_iucv_dev);
+       driver_unregister(&af_iucv_driver);
+       pr_iucv->iucv_unregister(&af_iucv_handler, 0);
+}
+
 static int __init afiucv_init(void)
 {
        int err;
@@ -2462,11 +2480,18 @@ static int __init afiucv_init(void)
                err = afiucv_iucv_init();
                if (err)
                        goto out_sock;
-       } else
-               register_netdevice_notifier(&afiucv_netdev_notifier);
+       }
+
+       err = register_netdevice_notifier(&afiucv_netdev_notifier);
+       if (err)
+               goto out_notifier;
+
        dev_add_pack(&iucv_packet_type);
        return 0;
 
+out_notifier:
+       if (pr_iucv)
+               afiucv_iucv_exit();
 out_sock:
        sock_unregister(PF_IUCV);
 out_proto:
@@ -2480,12 +2505,11 @@ out:
 static void __exit afiucv_exit(void)
 {
        if (pr_iucv) {
-               device_unregister(af_iucv_dev);
-               driver_unregister(&af_iucv_driver);
-               pr_iucv->iucv_unregister(&af_iucv_handler, 0);
+               afiucv_iucv_exit();
                symbol_put(iucv_if);
-       } else
-               unregister_netdevice_notifier(&afiucv_netdev_notifier);
+       }
+
+       unregister_netdevice_notifier(&afiucv_netdev_notifier);
        dev_remove_pack(&iucv_packet_type);
        sock_unregister(PF_IUCV);
        proto_unregister(&iucv_proto);