diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 33 |
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 | */ | ||
| 5379 | void 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. */ |
| 5366 | static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, | 5389 | static 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 | ||
