aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/associola.c15
-rw-r--r--net/sctp/endpointola.c7
-rw-r--r--net/sctp/input.c9
-rw-r--r--net/sctp/ipv6.c10
-rw-r--r--net/sctp/proc.c2
-rw-r--r--net/sctp/protocol.c2
-rw-r--r--net/sctp/socket.c33
-rw-r--r--net/sctp/ulpevent.c25
-rw-r--r--net/sctp/ulpqueue.c2
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. */
769void sctp_hash_established(struct sctp_association *asoc) 772void 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. */
802void sctp_unhash_established(struct sctp_association *asoc) 808void 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 */
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
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. */
58SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) 58SCTP_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. */
109static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) 112static 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