diff options
| author | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-03-31 15:17:41 -0400 |
|---|---|---|
| committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-04-07 17:06:25 -0400 |
| commit | baa7e1fa6d2870462bd744df1c6ddbd497fe86d6 (patch) | |
| tree | 44b459ce553a586e2fc8e43ba19d1e9a99a339da | |
| parent | 48454079c2d4b9ee65c570a22c5fdfe1827996a4 (diff) | |
Bluetooth: Use struct list_head for L2CAP channels list
Use a well known Kernel API is always a good idea than implement your own
list.
In the future we might use RCU on this list.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
| -rw-r--r-- | include/net/bluetooth/l2cap.h | 12 | ||||
| -rw-r--r-- | net/bluetooth/l2cap_core.c | 188 |
2 files changed, 88 insertions, 112 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 6378bcc94e2b..ddf4bc56a5b5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
| @@ -277,16 +277,9 @@ struct l2cap_conn_param_update_rsp { | |||
| 277 | #define L2CAP_CONN_PARAM_REJECTED 0x0001 | 277 | #define L2CAP_CONN_PARAM_REJECTED 0x0001 |
| 278 | 278 | ||
| 279 | /* ----- L2CAP channels and connections ----- */ | 279 | /* ----- L2CAP channels and connections ----- */ |
| 280 | |||
| 281 | struct l2cap_chan { | 280 | struct l2cap_chan { |
| 282 | struct sock *sk; | 281 | struct sock *sk; |
| 283 | struct l2cap_chan *next_c; | 282 | struct list_head list; |
| 284 | struct l2cap_chan *prev_c; | ||
| 285 | }; | ||
| 286 | |||
| 287 | struct l2cap_chan_list { | ||
| 288 | struct l2cap_chan *head; | ||
| 289 | rwlock_t lock; | ||
| 290 | }; | 283 | }; |
| 291 | 284 | ||
| 292 | struct l2cap_conn { | 285 | struct l2cap_conn { |
| @@ -312,7 +305,8 @@ struct l2cap_conn { | |||
| 312 | 305 | ||
| 313 | __u8 disc_reason; | 306 | __u8 disc_reason; |
| 314 | 307 | ||
| 315 | struct l2cap_chan_list chan_list; | 308 | struct list_head chan_l; |
| 309 | rwlock_t chan_lock; | ||
| 316 | }; | 310 | }; |
| 317 | 311 | ||
| 318 | struct sock_del_list { | 312 | struct sock_del_list { |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e49d8f7b80a5..0dbbaf394c13 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
| @@ -74,66 +74,75 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, | |||
| 74 | static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); | 74 | static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); |
| 75 | 75 | ||
| 76 | /* ---- L2CAP channels ---- */ | 76 | /* ---- L2CAP channels ---- */ |
| 77 | static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) | 77 | static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) |
| 78 | { | 78 | { |
| 79 | struct l2cap_chan *c; | 79 | struct l2cap_chan *c; |
| 80 | for (c = l->head; c; c = c->next_c) { | 80 | |
| 81 | if (l2cap_pi(c->sk)->dcid == cid) | 81 | list_for_each_entry(c, &conn->chan_l, list) { |
| 82 | break; | 82 | struct sock *s = c->sk; |
| 83 | if (l2cap_pi(s)->dcid == cid) | ||
| 84 | return c; | ||
| 83 | } | 85 | } |
| 84 | return c; | 86 | return NULL; |
| 87 | |||
| 85 | } | 88 | } |
| 86 | 89 | ||
| 87 | static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) | 90 | static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) |
| 88 | { | 91 | { |
| 89 | struct l2cap_chan *c; | 92 | struct l2cap_chan *c; |
| 90 | for (c = l->head; c; c = c->next_c) { | 93 | |
| 91 | if (l2cap_pi(c->sk)->scid == cid) | 94 | list_for_each_entry(c, &conn->chan_l, list) { |
| 92 | break; | 95 | struct sock *s = c->sk; |
| 96 | if (l2cap_pi(s)->scid == cid) | ||
| 97 | return c; | ||
| 93 | } | 98 | } |
| 94 | return c; | 99 | return NULL; |
| 95 | } | 100 | } |
| 96 | 101 | ||
| 97 | /* Find channel with given SCID. | 102 | /* Find channel with given SCID. |
| 98 | * Returns locked socket */ | 103 | * Returns locked socket */ |
| 99 | static inline struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) | 104 | static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) |
| 100 | { | 105 | { |
| 101 | struct l2cap_chan *c; | 106 | struct l2cap_chan *c; |
| 102 | read_lock(&l->lock); | 107 | |
| 103 | c = __l2cap_get_chan_by_scid(l, cid); | 108 | read_lock(&conn->chan_lock); |
| 109 | c = __l2cap_get_chan_by_scid(conn, cid); | ||
| 104 | if (c) | 110 | if (c) |
| 105 | bh_lock_sock(c->sk); | 111 | bh_lock_sock(c->sk); |
| 106 | read_unlock(&l->lock); | 112 | read_unlock(&conn->chan_lock); |
| 107 | return c; | 113 | return c; |
| 108 | } | 114 | } |
| 109 | 115 | ||
| 110 | static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) | 116 | static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) |
| 111 | { | 117 | { |
| 112 | struct l2cap_chan *c; | 118 | struct l2cap_chan *c; |
| 113 | for (c = l->head; c; c = c->next_c) { | 119 | |
| 114 | if (l2cap_pi(c->sk)->ident == ident) | 120 | list_for_each_entry(c, &conn->chan_l, list) { |
| 115 | break; | 121 | struct sock *s = c->sk; |
| 122 | if (l2cap_pi(s)->ident == ident) | ||
| 123 | return c; | ||
| 116 | } | 124 | } |
| 117 | return c; | 125 | return NULL; |
| 118 | } | 126 | } |
| 119 | 127 | ||
| 120 | static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) | 128 | static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) |
| 121 | { | 129 | { |
| 122 | struct l2cap_chan *c; | 130 | struct l2cap_chan *c; |
| 123 | read_lock(&l->lock); | 131 | |
| 124 | c = __l2cap_get_chan_by_ident(l, ident); | 132 | read_lock(&conn->chan_lock); |
| 133 | c = __l2cap_get_chan_by_ident(conn, ident); | ||
| 125 | if (c) | 134 | if (c) |
| 126 | bh_lock_sock(c->sk); | 135 | bh_lock_sock(c->sk); |
| 127 | read_unlock(&l->lock); | 136 | read_unlock(&conn->chan_lock); |
| 128 | return c; | 137 | return c; |
| 129 | } | 138 | } |
| 130 | 139 | ||
| 131 | static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) | 140 | static u16 l2cap_alloc_cid(struct l2cap_conn *conn) |
| 132 | { | 141 | { |
| 133 | u16 cid = L2CAP_CID_DYN_START; | 142 | u16 cid = L2CAP_CID_DYN_START; |
| 134 | 143 | ||
| 135 | for (; cid < L2CAP_CID_DYN_END; cid++) { | 144 | for (; cid < L2CAP_CID_DYN_END; cid++) { |
| 136 | if (!__l2cap_get_chan_by_scid(l, cid)) | 145 | if (!__l2cap_get_chan_by_scid(conn, cid)) |
| 137 | return cid; | 146 | return cid; |
| 138 | } | 147 | } |
| 139 | 148 | ||
| @@ -153,38 +162,8 @@ static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) | |||
| 153 | return chan; | 162 | return chan; |
| 154 | } | 163 | } |
| 155 | 164 | ||
| 156 | static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct l2cap_chan *chan) | ||
| 157 | { | ||
| 158 | sock_hold(chan->sk); | ||
| 159 | |||
| 160 | if (l->head) | ||
| 161 | l->head->prev_c = chan; | ||
| 162 | |||
| 163 | chan->next_c = l->head; | ||
| 164 | chan->prev_c = NULL; | ||
| 165 | l->head = chan; | ||
| 166 | } | ||
| 167 | |||
| 168 | static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct l2cap_chan *chan) | ||
| 169 | { | ||
| 170 | struct l2cap_chan *next = chan->next_c, *prev = chan->prev_c; | ||
| 171 | |||
| 172 | write_lock_bh(&l->lock); | ||
| 173 | if (chan == l->head) | ||
| 174 | l->head = next; | ||
| 175 | |||
| 176 | if (next) | ||
| 177 | next->prev_c = prev; | ||
| 178 | if (prev) | ||
| 179 | prev->next_c = next; | ||
| 180 | write_unlock_bh(&l->lock); | ||
| 181 | |||
| 182 | __sock_put(chan->sk); | ||
| 183 | } | ||
| 184 | |||
| 185 | static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) | 165 | static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) |
| 186 | { | 166 | { |
| 187 | struct l2cap_chan_list *l = &conn->chan_list; | ||
| 188 | struct sock *sk = chan->sk; | 167 | struct sock *sk = chan->sk; |
| 189 | 168 | ||
| 190 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, | 169 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, |
| @@ -202,7 +181,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) | |||
| 202 | l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; | 181 | l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; |
| 203 | |||
