Commit b3ccfbe4098a5542177d0f34e8979f32e7d606e1
Committed by
David S. Miller
1 parent
43e3692101
Exists in
master
and in
4 other branches
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, |
net/caif/chnl_net.c
... | ... | @@ -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 |