diff options
Diffstat (limited to 'drivers/net/pppol2tp.c')
-rw-r--r-- | drivers/net/pppol2tp.c | 77 |
1 files changed, 44 insertions, 33 deletions
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index e0b072d9fdb7..3d10ca050b79 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c | |||
@@ -302,14 +302,14 @@ pppol2tp_session_find(struct pppol2tp_tunnel *tunnel, u16 session_id) | |||
302 | struct pppol2tp_session *session; | 302 | struct pppol2tp_session *session; |
303 | struct hlist_node *walk; | 303 | struct hlist_node *walk; |
304 | 304 | ||
305 | read_lock(&tunnel->hlist_lock); | 305 | read_lock_bh(&tunnel->hlist_lock); |
306 | hlist_for_each_entry(session, walk, session_list, hlist) { | 306 | hlist_for_each_entry(session, walk, session_list, hlist) { |
307 | if (session->tunnel_addr.s_session == session_id) { | 307 | if (session->tunnel_addr.s_session == session_id) { |
308 | read_unlock(&tunnel->hlist_lock); | 308 | read_unlock_bh(&tunnel->hlist_lock); |
309 | return session; | 309 | return session; |
310 | } | 310 | } |
311 | } | 311 | } |
312 | read_unlock(&tunnel->hlist_lock); | 312 | read_unlock_bh(&tunnel->hlist_lock); |
313 | 313 | ||
314 | return NULL; | 314 | return NULL; |
315 | } | 315 | } |
@@ -320,14 +320,14 @@ static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id) | |||
320 | { | 320 | { |
321 | struct pppol2tp_tunnel *tunnel = NULL; | 321 | struct pppol2tp_tunnel *tunnel = NULL; |
322 | 322 | ||
323 | read_lock(&pppol2tp_tunnel_list_lock); | 323 | read_lock_bh(&pppol2tp_tunnel_list_lock); |
324 | list_for_each_entry(tunnel, &pppol2tp_tunnel_list, list) { | 324 | list_for_each_entry(tunnel, &pppol2tp_tunnel_list, list) { |
325 | if (tunnel->stats.tunnel_id == tunnel_id) { | 325 | if (tunnel->stats.tunnel_id == tunnel_id) { |
326 | read_unlock(&pppol2tp_tunnel_list_lock); | 326 | read_unlock_bh(&pppol2tp_tunnel_list_lock); |
327 | return tunnel; | 327 | return tunnel; |
328 | } | 328 | } |
329 | } | 329 | } |
330 | read_unlock(&pppol2tp_tunnel_list_lock); | 330 | read_unlock_bh(&pppol2tp_tunnel_list_lock); |
331 | 331 | ||
332 | return NULL; | 332 | return NULL; |
333 | } | 333 | } |
@@ -342,10 +342,11 @@ static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id) | |||
342 | static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb) | 342 | static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb) |
343 | { | 343 | { |
344 | struct sk_buff *skbp; | 344 | struct sk_buff *skbp; |
345 | struct sk_buff *tmp; | ||
345 | u16 ns = PPPOL2TP_SKB_CB(skb)->ns; | 346 | u16 ns = PPPOL2TP_SKB_CB(skb)->ns; |
346 | 347 | ||
347 | spin_lock(&session->reorder_q.lock); | 348 | spin_lock_bh(&session->reorder_q.lock); |
348 | skb_queue_walk(&session->reorder_q, skbp) { | 349 | skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { |
349 | if (PPPOL2TP_SKB_CB(skbp)->ns > ns) { | 350 | if (PPPOL2TP_SKB_CB(skbp)->ns > ns) { |
350 | __skb_insert(skb, skbp->prev, skbp, &session->reorder_q); | 351 | __skb_insert(skb, skbp->prev, skbp, &session->reorder_q); |
351 | PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, | 352 | PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, |
@@ -360,7 +361,7 @@ static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_ | |||
360 | __skb_queue_tail(&session->reorder_q, skb); | 361 | __skb_queue_tail(&session->reorder_q, skb); |
361 | 362 | ||
362 | out: | 363 | out: |
363 | spin_unlock(&session->reorder_q.lock); | 364 | spin_unlock_bh(&session->reorder_q.lock); |
364 | } | 365 | } |
365 | 366 | ||
366 | /* Dequeue a single skb. | 367 | /* Dequeue a single skb. |
@@ -371,10 +372,9 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s | |||
371 | int length = PPPOL2TP_SKB_CB(skb)->length; | 372 | int length = PPPOL2TP_SKB_CB(skb)->length; |
372 | struct sock *session_sock = NULL; | 373 | struct sock *session_sock = NULL; |
373 | 374 | ||
374 | /* We're about to requeue the skb, so unlink it and return resources | 375 | /* We're about to requeue the skb, so return resources |
375 | * to its current owner (a socket receive buffer). | 376 | * to its current owner (a socket receive buffer). |
376 | */ | 377 | */ |
377 | skb_unlink(skb, &session->reorder_q); | ||
378 | skb_orphan(skb); | 378 | skb_orphan(skb); |
379 | 379 | ||
380 | tunnel->stats.rx_packets++; | 380 | tunnel->stats.rx_packets++; |
@@ -442,7 +442,7 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session) | |||
442 | * expect to send up next, dequeue it and any other | 442 | * expect to send up next, dequeue it and any other |
443 | * in-sequence packets behind it. | 443 | * in-sequence packets behind it. |
444 | */ | 444 | */ |
445 | spin_lock(&session->reorder_q.lock); | 445 | spin_lock_bh(&session->reorder_q.lock); |
446 | skb_queue_walk_safe(&session->reorder_q, skb, tmp) { | 446 | skb_queue_walk_safe(&session->reorder_q, skb, tmp) { |
447 | if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) { | 447 | if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) { |
448 | session->stats.rx_seq_discards++; | 448 | session->stats.rx_seq_discards++; |
@@ -455,6 +455,7 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session) | |||
455 | skb_queue_len(&session->reorder_q)); | 455 | skb_queue_len(&session->reorder_q)); |
456 | __skb_unlink(skb, &session->reorder_q); | 456 | __skb_unlink(skb, &session->reorder_q); |
457 | kfree_skb(skb); | 457 | kfree_skb(skb); |
458 | sock_put(session->sock); | ||
458 | continue; | 459 | continue; |
459 | } | 460 | } |
460 | 461 | ||
@@ -469,13 +470,18 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session) | |||
469 | goto out; | 470 | goto out; |
470 | } | 471 | } |
471 | } | 472 | } |
472 | spin_unlock(&session->reorder_q.lock); | 473 | __skb_unlink(skb, &session->reorder_q); |
474 | |||
475 | /* Process the skb. We release the queue lock while we | ||
476 | * do so to let other contexts process the queue. | ||
477 | */ | ||
478 | spin_unlock_bh(&session->reorder_q.lock); | ||
473 | pppol2tp_recv_dequeue_skb(session, skb); | 479 | pppol2tp_recv_dequeue_skb(session, skb); |
474 | spin_lock(&session->reorder_q.lock); | 480 | spin_lock_bh(&session->reorder_q.lock); |
475 | } | 481 | } |
476 | 482 | ||
477 | out: | 483 | out: |
478 | spin_unlock(&session->reorder_q.lock); | 484 | spin_unlock_bh(&session->reorder_q.lock); |
479 | } | 485 | } |
480 | 486 | ||
481 | /* Internal receive frame. Do the real work of receiving an L2TP data frame | 487 | /* Internal receive frame. Do the real work of receiving an L2TP data frame |
@@ -1058,7 +1064,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
1058 | 1064 | ||
1059 | /* Get routing info from the tunnel socket */ | 1065 | /* Get routing info from the tunnel socket */ |
1060 | dst_release(skb->dst); | 1066 | dst_release(skb->dst); |
1061 | skb->dst = sk_dst_get(sk_tun); | 1067 | skb->dst = dst_clone(__sk_dst_get(sk_tun)); |
1062 | skb_orphan(skb); | 1068 | skb_orphan(skb); |
1063 | skb->sk = sk_tun; | 1069 | skb->sk = sk_tun; |
1064 | 1070 | ||
@@ -1106,10 +1112,12 @@ static void pppol2tp_tunnel_closeall(struct pppol2tp_tunnel *tunnel) | |||
1106 | PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, | 1112 | PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, |
1107 | "%s: closing all sessions...\n", tunnel->name); | 1113 | "%s: closing all sessions...\n", tunnel->name); |
1108 | 1114 | ||
1109 | write_lock(&tunnel->hlist_lock); | 1115 | write_lock_bh(&tunnel->hlist_lock); |
1110 | for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) { | 1116 | for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) { |
1111 | again: | 1117 | again: |
1112 | hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { | 1118 | hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { |
1119 | struct sk_buff *skb; | ||
1120 | |||
1113 | session = hlist_entry(walk, struct pppol2tp_session, hlist); | 1121 | session = hlist_entry(walk, struct pppol2tp_session, hlist); |
1114 | 1122 | ||
1115 | sk = session->sock; | 1123 | sk = session->sock; |
@@ -1126,7 +1134,7 @@ again: | |||
1126 | * disappear as we're jumping between locks. | 1134 | * disappear as we're jumping between locks. |
1127 | */ | 1135 | */ |
1128 | sock_hold(sk); | 1136 | sock_hold(sk); |
1129 | write_unlock(&tunnel->hlist_lock); | 1137 | write_unlock_bh(&tunnel->hlist_lock); |
1130 | lock_sock(sk); | 1138 | lock_sock(sk); |
1131 | 1139 | ||
1132 | if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { | 1140 | if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { |
@@ -1138,7 +1146,10 @@ again: | |||
1138 | /* Purge any queued data */ | 1146 | /* Purge any queued data */ |
1139 | skb_queue_purge(&sk->sk_receive_queue); | 1147 | skb_queue_purge(&sk->sk_receive_queue); |
1140 | skb_queue_purge(&sk->sk_write_queue); | 1148 | skb_queue_purge(&sk->sk_write_queue); |
1141 | skb_queue_purge(&session->reorder_q); | 1149 | while ((skb = skb_dequeue(&session->reorder_q))) { |
1150 | kfree_skb(skb); | ||
1151 | sock_put(sk); | ||
1152 | } | ||
1142 | 1153 | ||
1143 | release_sock(sk); | 1154 | release_sock(sk); |
1144 | sock_put(sk); | 1155 | sock_put(sk); |
@@ -1148,11 +1159,11 @@ again: | |||
1148 | * list so we are guaranteed to make forward | 1159 | * list so we are guaranteed to make forward |
1149 | * progress. | 1160 | * progress. |
1150 | */ | 1161 | */ |
1151 | write_lock(&tunnel->hlist_lock); | 1162 | write_lock_bh(&tunnel->hlist_lock); |
1152 | goto again; | 1163 | goto again; |
1153 | } | 1164 | } |
1154 | } | 1165 | } |
1155 | write_unlock(&tunnel->hlist_lock); | 1166 | write_unlock_bh(&tunnel->hlist_lock); |
1156 | } | 1167 | } |
1157 | 1168 | ||
1158 | /* Really kill the tunnel. | 1169 | /* Really kill the tunnel. |
@@ -1161,9 +1172,9 @@ again: | |||
1161 | static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel) | 1172 | static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel) |
1162 | { | 1173 | { |
1163 | /* Remove from socket list */ | 1174 | /* Remove from socket list */ |
1164 | write_lock(&pppol2tp_tunnel_list_lock); | 1175 | write_lock_bh(&pppol2tp_tunnel_list_lock); |
1165 | list_del_init(&tunnel->list); | 1176 | list_del_init(&tunnel->list); |
1166 | write_unlock(&pppol2tp_tunnel_list_lock); | 1177 | write_unlock_bh(&pppol2tp_tunnel_list_lock); |
1167 | 1178 | ||
1168 | atomic_dec(&pppol2tp_tunnel_count); | 1179 | atomic_dec(&pppol2tp_tunnel_count); |
1169 | kfree(tunnel); | 1180 | kfree(tunnel); |
@@ -1239,9 +1250,9 @@ static void pppol2tp_session_destruct(struct sock *sk) | |||
1239 | /* Delete the session socket from the | 1250 | /* Delete the session socket from the |
1240 | * hash | 1251 | * hash |
1241 | */ | 1252 | */ |
1242 | write_lock(&tunnel->hlist_lock); | 1253 | write_lock_bh(&tunnel->hlist_lock); |
1243 | hlist_del_init(&session->hlist); | 1254 | hlist_del_init(&session->hlist); |
1244 | write_unlock(&tunnel->hlist_lock); | 1255 | write_unlock_bh(&tunnel->hlist_lock); |
1245 | 1256 | ||
1246 | atomic_dec(&pppol2tp_session_count); | 1257 | atomic_dec(&pppol2tp_session_count); |
1247 | } | 1258 | } |
@@ -1386,9 +1397,9 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id, | |||
1386 | 1397 | ||
1387 | /* Add tunnel to our list */ | 1398 | /* Add tunnel to our list */ |
1388 | INIT_LIST_HEAD(&tunnel->list); | 1399 | INIT_LIST_HEAD(&tunnel->list); |
1389 | write_lock(&pppol2tp_tunnel_list_lock); | 1400 | write_lock_bh(&pppol2tp_tunnel_list_lock); |
1390 | list_add(&tunnel->list, &pppol2tp_tunnel_list); | 1401 | list_add(&tunnel->list, &pppol2tp_tunnel_list); |
1391 | write_unlock(&pppol2tp_tunnel_list_lock); | 1402 | write_unlock_bh(&pppol2tp_tunnel_list_lock); |
1392 | atomic_inc(&pppol2tp_tunnel_count); | 1403 | atomic_inc(&pppol2tp_tunnel_count); |
1393 | 1404 | ||
1394 | /* Bump the reference count. The tunnel context is deleted | 1405 | /* Bump the reference count. The tunnel context is deleted |
@@ -1593,11 +1604,11 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
1593 | sk->sk_user_data = session; | 1604 | sk->sk_user_data = session; |
1594 | 1605 | ||
1595 | /* Add session to the tunnel's hash list */ | 1606 | /* Add session to the tunnel's hash list */ |
1596 | write_lock(&tunnel->hlist_lock); | 1607 | write_lock_bh(&tunnel->hlist_lock); |
1597 | hlist_add_head(&session->hlist, | 1608 | hlist_add_head(&session->hlist, |
1598 | pppol2tp_session_id_hash(tunnel, | 1609 | pppol2tp_session_id_hash(tunnel, |
1599 | session->tunnel_addr.s_session)); | 1610 | session->tunnel_addr.s_session)); |
1600 | write_unlock(&tunnel->hlist_lock); | 1611 | write_unlock_bh(&tunnel->hlist_lock); |
1601 | 1612 | ||
1602 | atomic_inc(&pppol2tp_session_count); | 1613 | atomic_inc(&pppol2tp_session_count); |
1603 | 1614 | ||
@@ -2199,7 +2210,7 @@ static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, str | |||
2199 | int next = 0; | 2210 | int next = 0; |
2200 | int i; | 2211 | int i; |
2201 | 2212 | ||
2202 | read_lock(&tunnel->hlist_lock); | 2213 | read_lock_bh(&tunnel->hlist_lock); |
2203 | for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) { | 2214 | for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) { |
2204 | hlist_for_each_entry(session, walk, &tunnel->session_hlist[i], hlist) { | 2215 | hlist_for_each_entry(session, walk, &tunnel->session_hlist[i], hlist) { |
2205 | if (curr == NULL) { | 2216 | if (curr == NULL) { |
@@ -2217,7 +2228,7 @@ static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, str | |||
2217 | } | 2228 | } |
2218 | } | 2229 | } |
2219 | out: | 2230 | out: |
2220 | read_unlock(&tunnel->hlist_lock); | 2231 | read_unlock_bh(&tunnel->hlist_lock); |
2221 | if (!found) | 2232 | if (!found) |
2222 | session = NULL; | 2233 | session = NULL; |
2223 | 2234 | ||
@@ -2228,13 +2239,13 @@ static struct pppol2tp_tunnel *next_tunnel(struct pppol2tp_tunnel *curr) | |||
2228 | { | 2239 | { |
2229 | struct pppol2tp_tunnel *tunnel = NULL; | 2240 | struct pppol2tp_tunnel *tunnel = NULL; |
2230 | 2241 | ||
2231 | read_lock(&pppol2tp_tunnel_list_lock); | 2242 | read_lock_bh(&pppol2tp_tunnel_list_lock); |
2232 | if (list_is_last(&curr->list, &pppol2tp_tunnel_list)) { | 2243 | if (list_is_last(&curr->list, &pppol2tp_tunnel_list)) { |
2233 | goto out; | 2244 | goto out; |
2234 | } | 2245 | } |
2235 | tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list); | 2246 | tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list); |
2236 | out: | 2247 | out: |
2237 | read_unlock(&pppol2tp_tunnel_list_lock); | 2248 | read_unlock_bh(&pppol2tp_tunnel_list_lock); |
2238 | 2249 | ||
2239 | return tunnel; | 2250 | return tunnel; |
2240 | } | 2251 | } |