aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r--net/sctp/socket.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 3fe906d65069..935bc9187fd8 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -821,7 +821,7 @@ out:
821 * addrs is a pointer to an array of one or more socket addresses. Each 821 * addrs is a pointer to an array of one or more socket addresses. Each
822 * address is contained in its appropriate structure (i.e. struct 822 * address is contained in its appropriate structure (i.e. struct
823 * sockaddr_in or struct sockaddr_in6) the family of the address type 823 * sockaddr_in or struct sockaddr_in6) the family of the address type
824 * must be used to distengish the address length (note that this 824 * must be used to distinguish the address length (note that this
825 * representation is termed a "packed array" of addresses). The caller 825 * representation is termed a "packed array" of addresses). The caller
826 * specifies the number of addresses in the array with addrcnt. 826 * specifies the number of addresses in the array with addrcnt.
827 * 827 *
@@ -3372,6 +3372,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
3372{ 3372{
3373 struct sock *sk = asoc->base.sk; 3373 struct sock *sk = asoc->base.sk;
3374 struct socket *sock; 3374 struct socket *sock;
3375 struct inet_sock *inetsk;
3375 int err = 0; 3376 int err = 0;
3376 3377
3377 /* An association cannot be branched off from an already peeled-off 3378 /* An association cannot be branched off from an already peeled-off
@@ -3389,6 +3390,14 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
3389 * asoc to the newsk. 3390 * asoc to the newsk.
3390 */ 3391 */
3391 sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); 3392 sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
3393
3394 /* Make peeled-off sockets more like 1-1 accepted sockets.
3395 * Set the daddr and initialize id to something more random
3396 */
3397 inetsk = inet_sk(sock->sk);
3398 inetsk->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
3399 inetsk->id = asoc->next_tsn ^ jiffies;
3400
3392 *sockp = sock; 3401 *sockp = sock;
3393 3402
3394 return err; 3403 return err;
@@ -5362,6 +5371,20 @@ static void sctp_wfree(struct sk_buff *skb)
5362 sctp_association_put(asoc); 5371 sctp_association_put(asoc);
5363} 5372}
5364 5373
5374/* Do accounting for the receive space on the socket.
5375 * Accounting for the association is done in ulpevent.c
5376 * We set this as a destructor for the cloned data skbs so that
5377 * accounting is done at the correct time.
5378 */
5379void sctp_sock_rfree(struct sk_buff *skb)
5380{
5381 struct sock *sk = skb->sk;
5382 struct sctp_ulpevent *event = sctp_skb2event(skb);
5383
5384 atomic_sub(event->rmem_len, &sk->sk_rmem_alloc);
5385}
5386
5387
5365/* Helper function to wait for space in the sndbuf. */ 5388/* Helper function to wait for space in the sndbuf. */
5366static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 5389static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
5367 size_t msg_len) 5390 size_t msg_len)
@@ -5634,10 +5657,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
5634 sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { 5657 sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
5635 event = sctp_skb2event(skb); 5658 event = sctp_skb2event(skb);
5636 if (event->asoc == assoc) { 5659 if (event->asoc == assoc) {
5637 sock_rfree(skb); 5660 sctp_sock_rfree(skb);
5638 __skb_unlink(skb, &oldsk->sk_receive_queue); 5661 __skb_unlink(skb, &oldsk->sk_receive_queue);
5639 __skb_queue_tail(&newsk->sk_receive_queue, skb); 5662 __skb_queue_tail(&newsk->sk_receive_queue, skb);
5640 skb_set_owner_r(skb, newsk); 5663 sctp_skb_set_owner_r(skb, newsk);
5641 } 5664 }
5642 } 5665 }
5643 5666
@@ -5665,10 +5688,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
5665 sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { 5688 sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
5666 event = sctp_skb2event(skb); 5689 event = sctp_skb2event(skb);
5667 if (event->asoc == assoc) { 5690 if (event->asoc == assoc) {
5668 sock_rfree(skb); 5691 sctp_sock_rfree(skb);
5669 __skb_unlink(skb, &oldsp->pd_lobby); 5692 __skb_unlink(skb, &oldsp->pd_lobby);
5670 __skb_queue_tail(queue, skb); 5693 __skb_queue_tail(queue, skb);
5671 skb_set_owner_r(skb, newsk); 5694 sctp_skb_set_owner_r(skb, newsk);
5672 } 5695 }
5673 } 5696 }
5674 5697