diff options
author | sjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com> | 2011-05-13 02:44:04 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-15 17:45:55 -0400 |
commit | b3ccfbe4098a5542177d0f34e8979f32e7d606e1 (patch) | |
tree | 3f0046e3b519ea253db222abcb761af34b8a1718 /net/caif | |
parent | 43e3692101086add8719c3b8b50b05c9ac5b14e1 (diff) |
caif: Protected in-flight packets using dev or sock refcont.
CAIF Socket Layer and ip-interface registers reference counters
in CAIF service layer. The functions sock_hold, sock_put and
dev_hold, dev_put are used by CAIF Stack to protect from freeing
memory while packets are in-flight.
Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/caif')
-rw-r--r-- | net/caif/caif_socket.c | 19 | ||||
-rw-r--r-- | net/caif/chnl_net.c | 28 |
2 files changed, 43 insertions, 4 deletions
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 20212424e2e..01f612df7df 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -209,6 +209,18 @@ static int caif_sktrecv_cb(struct cflayer *layr, struct cfpkt *pkt) return 0; } +static void cfsk_hold(struct cflayer *layr) +{ + struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); + sock_hold(&cf_sk->sk); +} + +static void cfsk_put(struct cflayer *layr) +{ + struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); + sock_put(&cf_sk->sk); +} + /* Packet Control Callback function called from CAIF */ static void caif_ctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, @@ -232,6 +244,8 @@ static void caif_ctrl_cb(struct cflayer *layr, case CAIF_CTRLCMD_INIT_RSP: /* We're now connected */ + caif_client_register_refcnt(&cf_sk->layer, + cfsk_hold, cfsk_put); dbfs_atomic_inc(&cnt.num_connect_resp); cf_sk->sk.sk_state = CAIF_CONNECTED; set_tx_flow_on(cf_sk); @@ -242,7 +256,6 @@ static void caif_ctrl_cb(struct cflayer *layr, /* We're now disconnected */ cf_sk->sk.sk_state = CAIF_DISCONNECTED; cf_sk->sk.sk_state_change(&cf_sk->sk); - cfcnfg_release_adap_layer(&cf_sk->layer); break; case CAIF_CTRLCMD_INIT_FAIL_RSP: @@ -837,8 +850,10 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, dbfs_atomic_inc(&cnt.num_connect_req); cf_sk->layer.receive = caif_sktrecv_cb; + err = caif_connect_client(&cf_sk->conn_req, &cf_sk->layer, &ifindex, &headroom, &tailroom); + if (err < 0) { cf_sk->sk.sk_socket->state = SS_UNCONNECTED; cf_sk->sk.sk_state = CAIF_DISCONNECTED; @@ -940,7 +955,6 @@ static int caif_release(struct socket *sock) wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP); sock_orphan(sk); - cf_sk->layer.dn = NULL; sk_stream_kill_queues(&cf_sk->sk); release_sock(sk); sock_put(sk); @@ -1036,6 +1050,7 @@ static void caif_sock_destructor(struct sock *sk) } sk_stream_kill_queues(&cf_sk->sk); dbfs_atomic_dec(&cnt.caif_nr_socks); + caif_free_client(&cf_sk->layer); } static int caif_create(struct net *net, struct socket *sock, int protocol, diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index 6008d6dc18a..9ef8f1660ee 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c @@ -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; } |