diff options
author | sjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com> | 2011-05-22 07:18:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-22 20:11:47 -0400 |
commit | 54e90fb5ca8050156d3e748ddc690ed6ea9d71ac (patch) | |
tree | 63a4d1a736a7c44cc88b69e41dec9c4885ef2f74 /net/caif/cfmuxl.c | |
parent | 0e5a117441ce245b87949cc7713627a293f37227 (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/caif/cfmuxl.c')
-rw-r--r-- | net/caif/cfmuxl.c | 49 |
1 files changed, 38 insertions, 11 deletions
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 | ||
65 | int 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 | |||
75 | int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid) | 65 | int 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 | ||
86 | int 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 | |||
96 | struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid) | 104 | struct 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 | } |