diff options
Diffstat (limited to 'net/sctp')
| -rw-r--r-- | net/sctp/associola.c | 15 | ||||
| -rw-r--r-- | net/sctp/endpointola.c | 7 | ||||
| -rw-r--r-- | net/sctp/input.c | 9 | ||||
| -rw-r--r-- | net/sctp/ipv6.c | 10 | ||||
| -rw-r--r-- | net/sctp/proc.c | 2 | ||||
| -rw-r--r-- | net/sctp/protocol.c | 2 | ||||
| -rw-r--r-- | net/sctp/socket.c | 33 | ||||
| -rw-r--r-- | net/sctp/ulpevent.c | 25 | ||||
| -rw-r--r-- | net/sctp/ulpqueue.c | 2 |
9 files changed, 78 insertions, 27 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 27329ce9c311..ed0445fe85e7 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
| @@ -346,11 +346,18 @@ void sctp_association_free(struct sctp_association *asoc) | |||
| 346 | struct list_head *pos, *temp; | 346 | struct list_head *pos, *temp; |
| 347 | int i; | 347 | int i; |
| 348 | 348 | ||
| 349 | list_del(&asoc->asocs); | 349 | /* Only real associations count against the endpoint, so |
| 350 | * don't bother for if this is a temporary association. | ||
| 351 | */ | ||
| 352 | if (!asoc->temp) { | ||
| 353 | list_del(&asoc->asocs); | ||
| 350 | 354 | ||
| 351 | /* Decrement the backlog value for a TCP-style listening socket. */ | 355 | /* Decrement the backlog value for a TCP-style listening |
| 352 | if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) | 356 | * socket. |
| 353 | sk->sk_ack_backlog--; | 357 | */ |
| 358 | if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) | ||
| 359 | sk->sk_ack_backlog--; | ||
| 360 | } | ||
| 354 | 361 | ||
| 355 | /* Mark as dead, so other users can know this structure is | 362 | /* Mark as dead, so other users can know this structure is |
| 356 | * going away. | 363 | * going away. |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 35c49ff2d062..9b6b394b66f6 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
| @@ -144,6 +144,13 @@ void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, | |||
| 144 | { | 144 | { |
| 145 | struct sock *sk = ep->base.sk; | 145 | struct sock *sk = ep->base.sk; |
| 146 | 146 | ||
| 147 | /* If this is a temporary association, don't bother | ||
| 148 | * since we'll be removing it shortly and don't | ||
| 149 | * want anyone to find it anyway. | ||
| 150 | */ | ||
| 151 | if (asoc->temp) | ||
| 152 | return; | ||
| 153 | |||
| 147 | /* Now just add it to our list of asocs */ | 154 | /* Now just add it to our list of asocs */ |
| 148 | list_add_tail(&asoc->asocs, &ep->asocs); | 155 | list_add_tail(&asoc->asocs, &ep->asocs); |
| 149 | 156 | ||
diff --git a/net/sctp/input.c b/net/sctp/input.c index 64f630102532..6d82f400d13c 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
| @@ -135,6 +135,9 @@ int sctp_rcv(struct sk_buff *skb) | |||
| 135 | 135 | ||
| 136 | SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS); | 136 | SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS); |
| 137 | 137 | ||
| 138 | if (skb_linearize(skb)) | ||
| 139 | goto discard_it; | ||
| 140 | |||
| 138 | sh = (struct sctphdr *) skb->h.raw; | 141 | sh = (struct sctphdr *) skb->h.raw; |
| 139 | 142 | ||
| 140 | /* Pull up the IP and SCTP headers. */ | 143 | /* Pull up the IP and SCTP headers. */ |
| @@ -768,6 +771,9 @@ static void __sctp_hash_established(struct sctp_association *asoc) | |||
| 768 | /* Add an association to the hash. Local BH-safe. */ | 771 | /* Add an association to the hash. Local BH-safe. */ |
| 769 | void sctp_hash_established(struct sctp_association *asoc) | 772 | void sctp_hash_established(struct sctp_association *asoc) |
| 770 | { | 773 | { |
| 774 | if (asoc->temp) | ||
| 775 | return; | ||
| 776 | |||
| 771 | sctp_local_bh_disable(); | 777 | sctp_local_bh_disable(); |
| 772 | __sctp_hash_established(asoc); | 778 | __sctp_hash_established(asoc); |
| 773 | sctp_local_bh_enable(); | 779 | sctp_local_bh_enable(); |
| @@ -801,6 +807,9 @@ static void __sctp_unhash_established(struct sctp_association *asoc) | |||
| 801 | /* Remove association from the hash table. Local BH-safe. */ | 807 | /* Remove association from the hash table. Local BH-safe. */ |
| 802 | void sctp_unhash_established(struct sctp_association *asoc) | 808 | void sctp_unhash_established(struct sctp_association *asoc) |
| 803 | { | 809 | { |
| 810 | if (asoc->temp) | ||
| 811 | return; | ||
| 812 | |||
| 804 | sctp_local_bh_disable(); | 813 | sctp_local_bh_disable(); |
| 805 | __sctp_unhash_established(asoc); | 814 | __sctp_unhash_established(asoc); |
| 806 | sctp_local_bh_enable(); | 815 | sctp_local_bh_enable(); |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 249e5033c1a8..78071c6e6cf1 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
| @@ -215,17 +215,17 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, | |||
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | dst = ip6_route_output(NULL, &fl); | 217 | dst = ip6_route_output(NULL, &fl); |
| 218 | if (dst) { | 218 | if (!dst->error) { |
| 219 | struct rt6_info *rt; | 219 | struct rt6_info *rt; |
| 220 | rt = (struct rt6_info *)dst; | 220 | rt = (struct rt6_info *)dst; |
| 221 | SCTP_DEBUG_PRINTK( | 221 | SCTP_DEBUG_PRINTK( |
| 222 | "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n", | 222 | "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n", |
| 223 | NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr)); | 223 | NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr)); |
| 224 | } else { | 224 | return dst; |
| 225 | SCTP_DEBUG_PRINTK("NO ROUTE\n"); | ||
| 226 | } | 225 | } |
| 227 | 226 | SCTP_DEBUG_PRINTK("NO ROUTE\n"); | |
| 228 | return dst; | 227 | dst_release(dst); |
| 228 | return NULL; | ||
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | /* Returns the number of consecutive initial bits that match in the 2 ipv6 | 231 | /* Returns the number of consecutive initial bits that match in the 2 ipv6 |
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index a356d8d310a9..7f49e769080e 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
| @@ -344,7 +344,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | |||
| 344 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, | 344 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, |
| 345 | assoc->state, hash, assoc->assoc_id, | 345 | assoc->state, hash, assoc->assoc_id, |
| 346 | assoc->sndbuf_used, | 346 | assoc->sndbuf_used, |
| 347 | (sk->sk_rcvbuf - assoc->rwnd), | 347 | atomic_read(&assoc->rmem_alloc), |
| 348 | sock_i_uid(sk), sock_i_ino(sk), | 348 | sock_i_uid(sk), sock_i_ino(sk), |
| 349 | epb->bind_addr.port, | 349 | epb->bind_addr.port, |
| 350 | assoc->peer.port); | 350 | assoc->peer.port); |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index fac7674438a4..5b4f82fd98f8 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
| @@ -591,7 +591,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, | |||
| 591 | newinet->dport = htons(asoc->peer.port); | 591 | newinet->dport = htons(asoc->peer.port); |
| 592 | newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; | 592 | newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; |
| 593 | newinet->pmtudisc = inet->pmtudisc; | 593 | newinet->pmtudisc = inet->pmtudisc; |
| 594 | newinet->id = 0; | 594 | newinet->id = asoc->next_tsn ^ jiffies; |
| 595 | 595 | ||
| 596 | newinet->uc_ttl = -1; | 596 | newinet->uc_ttl = -1; |
| 597 | newinet->mc_loop = 1; | 597 | newinet->mc_loop = 1; |
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 | ||
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index ee236784a6bb..a015283a9087 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
| @@ -55,10 +55,13 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event); | |||
| 55 | 55 | ||
| 56 | 56 | ||
| 57 | /* Initialize an ULP event from an given skb. */ | 57 | /* Initialize an ULP event from an given skb. */ |
| 58 | SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) | 58 | SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, |
| 59 | int msg_flags, | ||
| 60 | unsigned int len) | ||
| 59 | { | 61 | { |
| 60 | memset(event, 0, sizeof(struct sctp_ulpevent)); | 62 | memset(event, 0, sizeof(struct sctp_ulpevent)); |
| 61 | event->msg_flags = msg_flags; | 63 | event->msg_flags = msg_flags; |
| 64 | event->rmem_len = len; | ||
| 62 | } | 65 | } |
| 63 | 66 | ||
| 64 | /* Create a new sctp_ulpevent. */ | 67 | /* Create a new sctp_ulpevent. */ |
| @@ -73,7 +76,7 @@ SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, | |||
| 73 | goto fail; | 76 | goto fail; |
| 74 | 77 | ||
| 75 | event = sctp_skb2event(skb); | 78 | event = sctp_skb2event(skb); |
| 76 | sctp_ulpevent_init(event, msg_flags); | 79 | sctp_ulpevent_init(event, msg_flags, skb->truesize); |
| 77 | 80 | ||
| 78 | return event; | 81 | return event; |
| 79 | 82 | ||
| @@ -101,17 +104,16 @@ static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, | |||
| 101 | sctp_association_hold((struct sctp_association *)asoc); | 104 | sctp_association_hold((struct sctp_association *)asoc); |
| 102 | skb = sctp_event2skb(event); | 105 | skb = sctp_event2skb(event); |
| 103 | event->asoc = (struct sctp_association *)asoc; | 106 | event->asoc = (struct sctp_association *)asoc; |
| 104 | atomic_add(skb->truesize, &event->asoc->rmem_alloc); | 107 | atomic_add(event->rmem_len, &event->asoc->rmem_alloc); |
| 105 | skb_set_owner_r(skb, asoc->base.sk); | 108 | sctp_skb_set_owner_r(skb, asoc->base.sk); |
| 106 | } | 109 | } |
| 107 | 110 | ||
| 108 | /* A simple destructor to give up the reference to the association. */ | 111 | /* A simple destructor to give up the reference to the association. */ |
| 109 | static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) | 112 | static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) |
| 110 | { | 113 | { |
| 111 | struct sctp_association *asoc = event->asoc; | 114 | struct sctp_association *asoc = event->asoc; |
| 112 | struct sk_buff *skb = sctp_event2skb(event); | ||
| 113 | 115 | ||
| 114 | atomic_sub(skb->truesize, &asoc->rmem_alloc); | 116 | atomic_sub(event->rmem_len, &asoc->rmem_alloc); |
| 115 | sctp_association_put(asoc); | 117 | sctp_association_put(asoc); |
| 116 | } | 118 | } |
| 117 | 119 | ||
| @@ -372,7 +374,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( | |||
| 372 | 374 | ||
| 373 | /* Embed the event fields inside the cloned skb. */ | 375 | /* Embed the event fields inside the cloned skb. */ |
| 374 | event = sctp_skb2event(skb); | 376 | event = sctp_skb2event(skb); |
| 375 | sctp_ulpevent_init(event, MSG_NOTIFICATION); | 377 | sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); |
| 376 | 378 | ||
| 377 | sre = (struct sctp_remote_error *) | 379 | sre = (struct sctp_remote_error *) |
| 378 | skb_push(skb, sizeof(struct sctp_remote_error)); | 380 | skb_push(skb, sizeof(struct sctp_remote_error)); |
| @@ -464,7 +466,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( | |||
| 464 | 466 | ||
| 465 | /* Embed the event fields inside the cloned skb. */ | 467 | /* Embed the event fields inside the cloned skb. */ |
| 466 | event = sctp_skb2event(skb); | 468 | event = sctp_skb2event(skb); |
| 467 | sctp_ulpevent_init(event, MSG_NOTIFICATION); | 469 | sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); |
| 468 | 470 | ||
| 469 | ssf = (struct sctp_send_failed *) | 471 | ssf = (struct sctp_send_failed *) |
| 470 | skb_push(skb, sizeof(struct sctp_send_failed)); | 472 | skb_push(skb, sizeof(struct sctp_send_failed)); |
| @@ -682,8 +684,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, | |||
| 682 | /* Embed the event fields inside the cloned skb. */ | 684 | /* Embed the event fields inside the cloned skb. */ |
| 683 | event = sctp_skb2event(skb); | 685 | event = sctp_skb2event(skb); |
| 684 | 686 | ||
| 685 | /* Initialize event with flags 0. */ | 687 | /* Initialize event with flags 0 and correct length |
| 686 | sctp_ulpevent_init(event, 0); | 688 | * Since this is a clone of the original skb, only account for |
| 689 | * the data of this chunk as other chunks will be accounted separately. | ||
| 690 | */ | ||
| 691 | sctp_ulpevent_init(event, 0, skb->len + sizeof(struct sk_buff)); | ||
| 687 | 692 | ||
| 688 | sctp_ulpevent_receive_data(event, asoc); | 693 | sctp_ulpevent_receive_data(event, asoc); |
| 689 | 694 | ||
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 575e556aeb3e..e1d144275f97 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c | |||
| @@ -309,7 +309,7 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu | |||
| 309 | if (!new) | 309 | if (!new) |
| 310 | return NULL; /* try again later */ | 310 | return NULL; /* try again later */ |
| 311 | 311 | ||
| 312 | new->sk = f_frag->sk; | 312 | sctp_skb_set_owner_r(new, f_frag->sk); |
| 313 | 313 | ||
| 314 | skb_shinfo(new)->frag_list = pos; | 314 | skb_shinfo(new)->frag_list = pos; |
| 315 | } else | 315 | } else |
