Commit b3ccfbe4098a5542177d0f34e8979f32e7d606e1

Authored by sjur.brandeland@stericsson.com
Committed by David S. Miller
1 parent 43e3692101

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>

Showing 3 changed files with 72 additions and 4 deletions Side-by-side Diff

include/net/caif/caif_dev.h
... ... @@ -74,6 +74,23 @@
74 74 int caif_disconnect_client(struct cflayer *client_layer);
75 75  
76 76 /**
  77 + * caif_client_register_refcnt - register ref-count functions provided by client.
  78 + *
  79 + * @adapt_layer: Client layer using CAIF Stack.
  80 + * @hold: Function provided by client layer increasing ref-count
  81 + * @put: Function provided by client layer decreasing ref-count
  82 + *
  83 + * Client of the CAIF Stack must register functions for reference counting.
  84 + * These functions are called by the CAIF Stack for every upstream packet,
  85 + * and must therefore be implemented efficiently.
  86 + *
  87 + * Client should call caif_free_client when reference count degrease to zero.
  88 + */
  89 +
  90 +void caif_client_register_refcnt(struct cflayer *adapt_layer,
  91 + void (*hold)(struct cflayer *lyr),
  92 + void (*put)(struct cflayer *lyr));
  93 +/**
77 94 * caif_connect_req_to_link_param - Translate configuration parameters
78 95 * from socket format to internal format.
79 96 * @cnfg: Pointer to configuration handler
80 97  
... ... @@ -83,9 +100,21 @@
83 100 * setting up channels.
84 101 *
85 102 */
  103 +
86 104 int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
87 105 struct caif_connect_request *con_req,
88 106 struct cfctrl_link_param *setup_param);
  107 +
  108 +/**
  109 + * caif_free_client - Free memory used to manage the client in the CAIF Stack.
  110 + *
  111 + * @client_layer: Client layer to be removed.
  112 + *
  113 + * This function must be called from client layer in order to free memory.
  114 + * Caller must guarantee that no packets are in flight upstream when calling
  115 + * this function.
  116 + */
  117 +void caif_free_client(struct cflayer *adap_layer);
89 118  
90 119 #endif /* CAIF_DEV_H_ */
net/caif/caif_socket.c
... ... @@ -209,6 +209,18 @@
209 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 224 /* Packet Control Callback function called from CAIF */
213 225 static void caif_ctrl_cb(struct cflayer *layr,
214 226 enum caif_ctrlcmd flow,
... ... @@ -232,6 +244,8 @@
232 244  
233 245 case CAIF_CTRLCMD_INIT_RSP:
234 246 /* We're now connected */
  247 + caif_client_register_refcnt(&cf_sk->layer,
  248 + cfsk_hold, cfsk_put);
235 249 dbfs_atomic_inc(&cnt.num_connect_resp);
236 250 cf_sk->sk.sk_state = CAIF_CONNECTED;
237 251 set_tx_flow_on(cf_sk);
... ... @@ -242,7 +256,6 @@
242 256 /* We're now disconnected */
243 257 cf_sk->sk.sk_state = CAIF_DISCONNECTED;
244 258 cf_sk->sk.sk_state_change(&cf_sk->sk);
245   - cfcnfg_release_adap_layer(&cf_sk->layer);
246 259 break;
247 260  
248 261 case CAIF_CTRLCMD_INIT_FAIL_RSP:
249 262  
... ... @@ -837,8 +850,10 @@
837 850  
838 851 dbfs_atomic_inc(&cnt.num_connect_req);
839 852 cf_sk->layer.receive = caif_sktrecv_cb;
  853 +
840 854 err = caif_connect_client(&cf_sk->conn_req,
841 855 &cf_sk->layer, &ifindex, &headroom, &tailroom);
  856 +
842 857 if (err < 0) {
843 858 cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
844 859 cf_sk->sk.sk_state = CAIF_DISCONNECTED;
... ... @@ -940,7 +955,6 @@
940 955 wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP);
941 956  
942 957 sock_orphan(sk);
943   - cf_sk->layer.dn = NULL;
944 958 sk_stream_kill_queues(&cf_sk->sk);
945 959 release_sock(sk);
946 960 sock_put(sk);
... ... @@ -1036,6 +1050,7 @@
1036 1050 }
1037 1051 sk_stream_kill_queues(&cf_sk->sk);
1038 1052 dbfs_atomic_dec(&cnt.caif_nr_socks);
  1053 + caif_free_client(&cf_sk->layer);
1039 1054 }
1040 1055  
1041 1056 static int caif_create(struct net *net, struct socket *sock, int protocol,
... ... @@ -153,6 +153,18 @@
153 153 }
154 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 168 static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
157 169 int phyid)
158 170 {
... ... @@ -190,6 +202,7 @@
190 202 netif_wake_queue(priv->netdev);
191 203 break;
192 204 case CAIF_CTRLCMD_INIT_RSP:
  205 + caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put);
193 206 priv->state = CAIF_CONNECTED;
194 207 priv->flowenabled = true;
195 208 netif_wake_queue(priv->netdev);
196 209  
... ... @@ -373,11 +386,18 @@
373 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 396 static void ipcaif_net_setup(struct net_device *dev)
377 397 {
378 398 struct chnl_net *priv;
379 399 dev->netdev_ops = &netdev_ops;
380   - dev->destructor = free_netdev;
  400 + dev->destructor = chnl_net_destructor;
381 401 dev->flags |= IFF_NOARP;
382 402 dev->flags |= IFF_POINTOPOINT;
383 403 dev->mtu = GPRS_PDP_MTU;
... ... @@ -391,7 +411,7 @@
391 411 priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW;
392 412 priv->conn_req.priority = CAIF_PRIO_LOW;
393 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 415 priv->flowenabled = false;
396 416  
397 417 init_waitqueue_head(&priv->netmgmt_wq);
... ... @@ -453,6 +473,10 @@
453 473 pr_warn("device rtml registration failed\n");
454 474 else
455 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 480 return ret;
457 481 }
458 482