caif: Protected in-flight packets using dev or sock refcont.
[firefly-linux-kernel-4.4.55.git] / net / caif / chnl_net.c
index 6008d6dc18a02283fdff763ba2186190208a8003..9ef8f1660ee1450045626afe180c81f934e3c9fe 100644 (file)
@@ -153,6 +153,18 @@ static void close_work(struct work_struct *work)
 }
 static DECLARE_WORK(close_worker, close_work);
 
+static void chnl_hold(struct cflayer *lyr)
+{
+       struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl);
+       dev_hold(priv->netdev);
+}
+
+static void chnl_put(struct cflayer *lyr)
+{
+       struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl);
+       dev_put(priv->netdev);
+}
+
 static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
                                int phyid)
 {
@@ -190,6 +202,7 @@ static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
                netif_wake_queue(priv->netdev);
                break;
        case CAIF_CTRLCMD_INIT_RSP:
+               caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put);
                priv->state = CAIF_CONNECTED;
                priv->flowenabled = true;
                netif_wake_queue(priv->netdev);
@@ -373,11 +386,18 @@ static const struct net_device_ops netdev_ops = {
        .ndo_start_xmit = chnl_net_start_xmit,
 };
 
+static void chnl_net_destructor(struct net_device *dev)
+{
+       struct chnl_net *priv = netdev_priv(dev);
+       caif_free_client(&priv->chnl);
+       free_netdev(dev);
+}
+
 static void ipcaif_net_setup(struct net_device *dev)
 {
        struct chnl_net *priv;
        dev->netdev_ops = &netdev_ops;
-       dev->destructor = free_netdev;
+       dev->destructor = chnl_net_destructor;
        dev->flags |= IFF_NOARP;
        dev->flags |= IFF_POINTOPOINT;
        dev->mtu = GPRS_PDP_MTU;
@@ -391,7 +411,7 @@ static void ipcaif_net_setup(struct net_device *dev)
        priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW;
        priv->conn_req.priority = CAIF_PRIO_LOW;
        /* Insert illegal value */
-       priv->conn_req.sockaddr.u.dgm.connection_id = -1;
+       priv->conn_req.sockaddr.u.dgm.connection_id = 0;
        priv->flowenabled = false;
 
        init_waitqueue_head(&priv->netmgmt_wq);
@@ -453,6 +473,10 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
                pr_warn("device rtml registration failed\n");
        else
                list_add(&caifdev->list_field, &chnl_net_list);
+
+       /* Take ifindex as connection-id if null */
+       if (caifdev->conn_req.sockaddr.u.dgm.connection_id == 0)
+               caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex;
        return ret;
 }