aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorsjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com>2011-05-22 07:18:51 -0400
committerDavid S. Miller <davem@davemloft.net>2011-05-22 20:11:47 -0400
commit54e90fb5ca8050156d3e748ddc690ed6ea9d71ac (patch)
tree63a4d1a736a7c44cc88b69e41dec9c4885ef2f74 /net
parent0e5a117441ce245b87949cc7713627a293f37227 (diff)
caif: Fixes freeze on Link layer removal.
CAIF Socket layer - caif_socket.c: - Plug mem-leak at reconnect. - Always call disconnect to cleanup CAIF stack. - Disconnect will always report success. CAIF configuration layer - cfcnfg.c - Disconnect must dismantle the caif stack correctly - Protect against faulty removals (check on id zero) CAIF mux layer - cfmuxl.c - When inserting new service layer in the MUX remove any old entries with the same ID. - When removing CAIF Link layer, remove the associated service layers before notifying service layers. Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/caif/caif_socket.c13
-rw-r--r--net/caif/cfcnfg.c44
-rw-r--r--net/caif/cfmuxl.c49
3 files changed, 62 insertions, 44 deletions
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index b840395ced1d..a98628086452 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -19,7 +19,7 @@
19#include <linux/uaccess.h> 19#include <linux/uaccess.h>
20#include <linux/debugfs.h> 20#include <linux/debugfs.h>
21#include <linux/caif/caif_socket.h> 21#include <linux/caif/caif_socket.h>
22#include <asm/atomic.h> 22#include <linux/atomic.h>
23#include <net/sock.h> 23#include <net/sock.h>
24#include <net/tcp_states.h> 24#include <net/tcp_states.h>
25#include <net/caif/caif_layer.h> 25#include <net/caif/caif_layer.h>
@@ -816,6 +816,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
816 if (sk->sk_shutdown & SHUTDOWN_MASK) { 816 if (sk->sk_shutdown & SHUTDOWN_MASK) {
817 /* Allow re-connect after SHUTDOWN_IND */ 817 /* Allow re-connect after SHUTDOWN_IND */
818 caif_disconnect_client(sock_net(sk), &cf_sk->layer); 818 caif_disconnect_client(sock_net(sk), &cf_sk->layer);
819 caif_free_client(&cf_sk->layer);
819 break; 820 break;
820 } 821 }
821 /* No reconnect on a seqpacket socket */ 822 /* No reconnect on a seqpacket socket */
@@ -926,7 +927,6 @@ static int caif_release(struct socket *sock)
926{ 927{
927 struct sock *sk = sock->sk; 928 struct sock *sk = sock->sk;
928 struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); 929 struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
929 int res = 0;
930 930
931 if (!sk) 931 if (!sk)
932 return 0; 932 return 0;
@@ -953,10 +953,7 @@ static int caif_release(struct socket *sock)
953 sk->sk_state = CAIF_DISCONNECTED; 953 sk->sk_state = CAIF_DISCONNECTED;
954 sk->sk_shutdown = SHUTDOWN_MASK; 954 sk->sk_shutdown = SHUTDOWN_MASK;
955 955
956 if (cf_sk->sk.sk_socket->state == SS_CONNECTED || 956 caif_disconnect_client(sock_net(sk), &cf_sk->layer);
957 cf_sk->sk.sk_socket->state == SS_CONNECTING)
958 res = caif_disconnect_client(sock_net(sk), &cf_sk->layer);
959
960 cf_sk->sk.sk_socket->state = SS_DISCONNECTING; 957 cf_sk->sk.sk_socket->state = SS_DISCONNECTING;
961 wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP); 958 wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP);
962 959
@@ -964,7 +961,7 @@ static int caif_release(struct socket *sock)
964 sk_stream_kill_queues(&cf_sk->sk); 961 sk_stream_kill_queues(&cf_sk->sk);
965 release_sock(sk); 962 release_sock(sk);
966 sock_put(sk); 963 sock_put(sk);
967 return res; 964 return 0;
968} 965}
969 966
970/* Copied from af_unix.c:unix_poll(), added CAIF tx_flow handling */ 967/* Copied from af_unix.c:unix_poll(), added CAIF tx_flow handling */
@@ -1120,7 +1117,7 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
1120 set_rx_flow_on(cf_sk); 1117 set_rx_flow_on(cf_sk);
1121 1118
1122 /* Set default options on configuration */ 1119 /* Set default options on configuration */
1123 cf_sk->sk.sk_priority= CAIF_PRIO_NORMAL; 1120 cf_sk->sk.sk_priority = CAIF_PRIO_NORMAL;
1124 cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY; 1121 cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY;
1125 cf_sk->conn_req.protocol = protocol; 1122 cf_sk->conn_req.protocol = protocol;
1126 /* Increase the number of sockets created. */ 1123 /* Increase the number of sockets created. */
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index 351c2ca7e7b9..52fe33bee029 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -182,39 +182,26 @@ static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
182 182
183int caif_disconnect_client(struct net *net, struct cflayer *adap_layer) 183int caif_disconnect_client(struct net *net, struct cflayer *adap_layer)
184{ 184{
185 u8 channel_id = 0; 185 u8 channel_id;
186 int ret = 0;
187 struct cflayer *servl = NULL;
188 struct cfcnfg *cfg = get_cfcnfg(net); 186 struct cfcnfg *cfg = get_cfcnfg(net);
189 187
190 caif_assert(adap_layer != NULL); 188 caif_assert(adap_layer != NULL);
191
192 channel_id = adap_layer->id;
193 if (adap_layer->dn == NULL || channel_id == 0) {
194 pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n");
195 ret = -ENOTCONN;
196 goto end;
197 }
198
199 servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
200 if (servl == NULL) {
201 pr_err("PROTOCOL ERROR - "
202 "Error removing service_layer Channel_Id(%d)",
203 channel_id);
204 ret = -EINVAL;
205 goto end;
206 }
207
208 ret = cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
209
210end:
211 cfctrl_cancel_req(cfg->ctrl, adap_layer); 189 cfctrl_cancel_req(cfg->ctrl, adap_layer);
190 channel_id = adap_layer->id;
191 if (channel_id != 0) {
192 struct cflayer *servl;
193 servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
194 if (servl != NULL)
195 layer_set_up(servl, NULL);
196 } else
197 pr_debug("nothing to disconnect\n");
198 cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
212 199
213 /* Do RCU sync before initiating cleanup */ 200 /* Do RCU sync before initiating cleanup */
214 synchronize_rcu(); 201 synchronize_rcu();
215 if (adap_layer->ctrlcmd != NULL) 202 if (adap_layer->ctrlcmd != NULL)
216 adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0); 203 adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
217 return ret; 204 return 0;
218 205
219} 206}
220EXPORT_SYMBOL(caif_disconnect_client); 207EXPORT_SYMBOL(caif_disconnect_client);
@@ -400,6 +387,14 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
400 struct cfcnfg_phyinfo *phyinfo; 387 struct cfcnfg_phyinfo *phyinfo;
401 struct net_device *netdev; 388 struct net_device *netdev;
402 389
390 if (channel_id == 0) {
391 pr_warn("received channel_id zero\n");
392 if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
393 adapt_layer->ctrlcmd(adapt_layer,
394 CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
395 return;
396 }
397
403 rcu_read_lock(); 398 rcu_read_lock();
404 399
405 if (adapt_layer == NULL) { 400 if (adapt_layer == NULL) {
@@ -523,7 +518,6 @@ got_phyid:
523 phyinfo->use_stx = stx; 518 phyinfo->use_stx = stx;
524 phyinfo->use_fcs = fcs; 519 phyinfo->use_fcs = fcs;
525 520
526 phy_layer->type = phy_type;
527 frml = cffrml_create(phyid, fcs); 521 frml = cffrml_create(phyid, fcs);
528 522
529 if (!frml) { 523 if (!frml) {
diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c
index 2a56df7e0a4b..3a66b8c10e09 100644
--- a/net/caif/cfmuxl.c
+++ b/net/caif/cfmuxl.c
@@ -62,16 +62,6 @@ struct cflayer *cfmuxl_create(void)
62 return &this->layer; 62 return &this->layer;
63} 63}
64 64
65int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid)
66{
67 struct cfmuxl *muxl = container_obj(layr);
68
69 spin_lock_bh(&muxl->receive_lock);
70 list_add_rcu(&up->node, &muxl->srvl_list);
71 spin_unlock_bh(&muxl->receive_lock);
72 return 0;
73}
74
75int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid) 65int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid)
76{ 66{
77 struct cfmuxl *muxl = (struct cfmuxl *) layr; 67 struct cfmuxl *muxl = (struct cfmuxl *) layr;
@@ -93,6 +83,24 @@ static struct cflayer *get_from_id(struct list_head *list, u16 id)
93 return NULL; 83 return NULL;
94} 84}
95 85
86int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid)
87{
88 struct cfmuxl *muxl = container_obj(layr);
89 struct cflayer *old;
90
91 spin_lock_bh(&muxl->receive_lock);
92
93 /* Two entries with same id is wrong, so remove old layer from mux */
94 old = get_from_id(&muxl->srvl_list, linkid);
95 if (old != NULL)
96 list_del_rcu(&old->node);
97
98 list_add_rcu(&up->node, &muxl->srvl_list);
99 spin_unlock_bh(&muxl->receive_lock);
100
101 return 0;
102}
103
96struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid) 104struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid)
97{ 105{
98 struct cfmuxl *muxl = container_obj(layr); 106 struct cfmuxl *muxl = container_obj(layr);
@@ -146,6 +154,11 @@ struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 id)
146 struct cfmuxl *muxl = container_obj(layr); 154 struct cfmuxl *muxl = container_obj(layr);
147 int idx = id % UP_CACHE_SIZE; 155 int idx = id % UP_CACHE_SIZE;
148 156
157 if (id == 0) {
158 pr_warn("Trying to remove control layer\n");
159 return NULL;
160 }
161
149 spin_lock_bh(&muxl->receive_lock); 162 spin_lock_bh(&muxl->receive_lock);
150 up = get_from_id(&muxl->srvl_list, id); 163 up = get_from_id(&muxl->srvl_list, id);
151 if (up == NULL) 164 if (up == NULL)
@@ -235,12 +248,26 @@ static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
235{ 248{
236 struct cfmuxl *muxl = container_obj(layr); 249 struct cfmuxl *muxl = container_obj(layr);
237 struct cflayer *layer; 250 struct cflayer *layer;
251 int idx;
238 252
239 rcu_read_lock(); 253 rcu_read_lock();
240 list_for_each_entry_rcu(layer, &muxl->srvl_list, node) { 254 list_for_each_entry_rcu(layer, &muxl->srvl_list, node) {
241 if (cfsrvl_phyid_match(layer, phyid) && layer->ctrlcmd) 255
256 if (cfsrvl_phyid_match(layer, phyid) && layer->ctrlcmd) {
257
258 if ((ctrl == _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND ||
259 ctrl == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND) &&
260 layer->id != 0) {
261
262 idx = layer->id % UP_CACHE_SIZE;
263 spin_lock_bh(&muxl->receive_lock);
264 rcu_assign_pointer(muxl->up_cache[idx], NULL);
265 list_del_rcu(&layer->node);
266 spin_unlock_bh(&muxl->receive_lock);
267 }
242 /* NOTE: ctrlcmd is not allowed to block */ 268 /* NOTE: ctrlcmd is not allowed to block */
243 layer->ctrlcmd(layer, ctrl, phyid); 269 layer->ctrlcmd(layer, ctrl, phyid);
270 }
244 } 271 }
245 rcu_read_unlock(); 272 rcu_read_unlock();
246} 273}