diff options
author | sjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com> | 2011-05-12 22:44:04 -0400 |
---|---|---|
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 20212424e2e8..01f612df7df1 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) | |||
209 | return 0; | 209 | return 0; |
210 | } | 210 | } |
211 | 211 | ||
212 | static void cfsk_hold(struct cflayer *layr) | ||
213 | { | ||
214 | struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); | ||
215 | sock_hold(&cf_sk->sk); | ||
216 | } | ||
217 | |||
218 | static void cfsk_put(struct cflayer *layr) | ||
219 | { | ||
220 | struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); | ||
221 | sock_put(&cf_sk->sk); | ||
222 | } | ||
223 | |||
212 | /* Packet Control Callback function called from CAIF */ | 224 | /* Packet Control Callback function called from CAIF */ |
213 | static void caif_ctrl_cb(struct cflayer *layr, | 225 | static void caif_ctrl_cb(struct cflayer *layr, |
214 | enum caif_ctrlcmd flow, | 226 | enum caif_ctrlcmd flow, |
@@ -232,6 +244,8 @@ static void caif_ctrl_cb(struct cflayer *layr, | |||
232 | 244 | ||
233 | case CAIF_CTRLCMD_INIT_RSP: | 245 | case CAIF_CTRLCMD_INIT_RSP: |
234 | /* We're now connected */ | 246 | /* We're now connected */ |
247 | caif_client_register_refcnt(&cf_sk->layer, | ||
248 | cfsk_hold, cfsk_put); | ||
235 | dbfs_atomic_inc(&cnt.num_connect_resp); | 249 | dbfs_atomic_inc(&cnt.num_connect_resp); |
236 | cf_sk->sk.sk_state = CAIF_CONNECTED; | 250 | cf_sk->sk.sk_state = CAIF_CONNECTED; |
237 | set_tx_flow_on(cf_sk); | 251 | set_tx_flow_on(cf_sk); |
@@ -242,7 +256,6 @@ static void caif_ctrl_cb(struct cflayer *layr, | |||
242 | /* We're now disconnected */ | 256 | /* We're now disconnected */ |
243 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; | 257 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; |
244 | cf_sk->sk.sk_state_change(&cf_sk->sk); | 258 | cf_sk->sk.sk_state_change(&cf_sk->sk); |
245 | cfcnfg_release_adap_layer(&cf_sk->layer); | ||
246 | break; | 259 | break; |
247 | 260 | ||
248 | case CAIF_CTRLCMD_INIT_FAIL_RSP: | 261 | case CAIF_CTRLCMD_INIT_FAIL_RSP: |
@@ -837,8 +850,10 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, | |||
837 | 850 | ||
838 | dbfs_atomic_inc(&cnt.num_connect_req); | 851 | dbfs_atomic_inc(&cnt.num_connect_req); |
839 | cf_sk->layer.receive = caif_sktrecv_cb; | 852 | cf_sk->layer.receive = caif_sktrecv_cb; |
853 | |||
840 | err = caif_connect_client(&cf_sk->conn_req, | 854 | err = caif_connect_client(&cf_sk->conn_req, |
841 | &cf_sk->layer, &ifindex, &headroom, &tailroom); | 855 | &cf_sk->layer, &ifindex, &headroom, &tailroom); |
856 | |||
842 | if (err < 0) { | 857 | if (err < 0) { |
843 | cf_sk->sk.sk_socket->state = SS_UNCONNECTED; | 858 | cf_sk->sk.sk_socket->state = SS_UNCONNECTED; |
844 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; | 859 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; |
@@ -940,7 +955,6 @@ static int caif_release(struct socket *sock) | |||
940 | wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP); | 955 | wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP); |
941 | 956 | ||
942 | sock_orphan(sk); | 957 | sock_orphan(sk); |
943 | cf_sk->layer.dn = NULL; | ||
944 | sk_stream_kill_queues(&cf_sk->sk); | 958 | sk_stream_kill_queues(&cf_sk->sk); |
945 | release_sock(sk); | 959 | release_sock(sk); |
946 | sock_put(sk); | 960 | sock_put(sk); |
@@ -1036,6 +1050,7 @@ static void caif_sock_destructor(struct sock *sk) | |||
1036 | } | 1050 | } |
1037 | sk_stream_kill_queues(&cf_sk->sk); | 1051 | sk_stream_kill_queues(&cf_sk->sk); |
1038 | dbfs_atomic_dec(&cnt.caif_nr_socks); | 1052 | dbfs_atomic_dec(&cnt.caif_nr_socks); |
1053 | caif_free_client(&cf_sk->layer); | ||
1039 | } | 1054 | } |
1040 | 1055 | ||
1041 | static int caif_create(struct net *net, struct socket *sock, int protocol, | 1056 | 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 6008d6dc18a0..9ef8f1660ee1 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) | |||
153 | } | 153 | } |
154 | static DECLARE_WORK(close_worker, close_work); | 154 | static DECLARE_WORK(close_worker, close_work); |
155 | 155 | ||
156 | static void chnl_hold(struct cflayer *lyr) | ||
157 | { | ||
158 | struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl); | ||
159 | dev_hold(priv->netdev); | ||
160 | } | ||
161 | |||
162 | static void chnl_put(struct cflayer *lyr) | ||
163 | { | ||
164 | struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl); | ||
165 | dev_put(priv->netdev); | ||
166 | } | ||
167 | |||
156 | static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, | 168 | static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, |
157 | int phyid) | 169 | int phyid) |
158 | { | 170 | { |
@@ -190,6 +202,7 @@ static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, | |||
190 | netif_wake_queue(priv->netdev); | 202 | netif_wake_queue(priv->netdev); |
191 | break; | 203 | break; |
192 | case CAIF_CTRLCMD_INIT_RSP: | 204 | case CAIF_CTRLCMD_INIT_RSP: |
205 | caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put); | ||
193 | priv->state = CAIF_CONNECTED; | 206 | priv->state = CAIF_CONNECTED; |
194 | priv->flowenabled = true; | 207 | priv->flowenabled = true; |
195 | netif_wake_queue(priv->netdev); | 208 | netif_wake_queue(priv->netdev); |
@@ -373,11 +386,18 @@ static const struct net_device_ops netdev_ops = { | |||
373 | .ndo_start_xmit = chnl_net_start_xmit, | 386 | .ndo_start_xmit = chnl_net_start_xmit, |
374 | }; | 387 | }; |
375 | 388 | ||
389 | static void chnl_net_destructor(struct net_device *dev) | ||
390 | { | ||
391 | struct chnl_net *priv = netdev_priv(dev); | ||
392 | caif_free_client(&priv->chnl); | ||
393 | free_netdev(dev); | ||
394 | } | ||
395 | |||
376 | static void ipcaif_net_setup(struct net_device *dev) | 396 | static void ipcaif_net_setup(struct net_device *dev) |
377 | { | 397 | { |
378 | struct chnl_net *priv; | 398 | struct chnl_net *priv; |
379 | dev->netdev_ops = &netdev_ops; | 399 | dev->netdev_ops = &netdev_ops; |
380 | dev->destructor = free_netdev; | 400 | dev->destructor = chnl_net_destructor; |
381 | dev->flags |= IFF_NOARP; | 401 | dev->flags |= IFF_NOARP; |
382 | dev->flags |= IFF_POINTOPOINT; | 402 | dev->flags |= IFF_POINTOPOINT; |
383 | dev->mtu = GPRS_PDP_MTU; | 403 | dev->mtu = GPRS_PDP_MTU; |
@@ -391,7 +411,7 @@ static void ipcaif_net_setup(struct net_device *dev) | |||
391 | priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW; | 411 | priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW; |
392 | priv->conn_req.priority = CAIF_PRIO_LOW; | 412 | priv->conn_req.priority = CAIF_PRIO_LOW; |
393 | /* Insert illegal value */ | 413 | /* Insert illegal value */ |
394 | priv->conn_req.sockaddr.u.dgm.connection_id = -1; | 414 | priv->conn_req.sockaddr.u.dgm.connection_id = 0; |
395 | priv->flowenabled = false; | 415 | priv->flowenabled = false; |
396 | 416 | ||
397 | init_waitqueue_head(&priv->netmgmt_wq); | 417 | init_waitqueue_head(&priv->netmgmt_wq); |
@@ -453,6 +473,10 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev, | |||
453 | pr_warn("device rtml registration failed\n"); | 473 | pr_warn("device rtml registration failed\n"); |
454 | else | 474 | else |
455 | list_add(&caifdev->list_field, &chnl_net_list); | 475 | list_add(&caifdev->list_field, &chnl_net_list); |
476 | |||
477 | /* Take ifindex as connection-id if null */ | ||
478 | if (caifdev->conn_req.sockaddr.u.dgm.connection_id == 0) | ||
479 | caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex; | ||
456 | return ret; | 480 | return ret; |
457 | } | 481 | } |
458 | 482 | ||