diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index e8c210182571..0b338eca6dc0 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -115,9 +115,17 @@ static inline int sctp_wspace(struct sctp_association *asoc) | |||
115 | struct sock *sk = asoc->base.sk; | 115 | struct sock *sk = asoc->base.sk; |
116 | int amt = 0; | 116 | int amt = 0; |
117 | 117 | ||
118 | amt = sk->sk_sndbuf - asoc->sndbuf_used; | 118 | if (asoc->ep->sndbuf_policy) { |
119 | /* make sure that no association uses more than sk_sndbuf */ | ||
120 | amt = sk->sk_sndbuf - asoc->sndbuf_used; | ||
121 | } else { | ||
122 | /* do socket level accounting */ | ||
123 | amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); | ||
124 | } | ||
125 | |||
119 | if (amt < 0) | 126 | if (amt < 0) |
120 | amt = 0; | 127 | amt = 0; |
128 | |||
121 | return amt; | 129 | return amt; |
122 | } | 130 | } |
123 | 131 | ||
@@ -138,12 +146,21 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) | |||
138 | /* The sndbuf space is tracked per association. */ | 146 | /* The sndbuf space is tracked per association. */ |
139 | sctp_association_hold(asoc); | 147 | sctp_association_hold(asoc); |
140 | 148 | ||
149 | skb_set_owner_w(chunk->skb, sk); | ||
150 | |||
141 | chunk->skb->destructor = sctp_wfree; | 151 | chunk->skb->destructor = sctp_wfree; |
142 | /* Save the chunk pointer in skb for sctp_wfree to use later. */ | 152 | /* Save the chunk pointer in skb for sctp_wfree to use later. */ |
143 | *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; | 153 | *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; |
144 | 154 | ||
145 | asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); | 155 | asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) + |
146 | sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); | 156 | sizeof(struct sk_buff) + |
157 | sizeof(struct sctp_chunk); | ||
158 | |||
159 | sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk) + | ||
160 | sizeof(struct sk_buff) + | ||
161 | sizeof(struct sctp_chunk); | ||
162 | |||
163 | atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); | ||
147 | } | 164 | } |
148 | 165 | ||
149 | /* Verify that this is a valid address. */ | 166 | /* Verify that this is a valid address. */ |
@@ -3473,7 +3490,7 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len, | |||
3473 | return -EINVAL; | 3490 | return -EINVAL; |
3474 | 3491 | ||
3475 | /* Values correspoinding to the specific association */ | 3492 | /* Values correspoinding to the specific association */ |
3476 | if (assocparams.sasoc_assoc_id != 0) { | 3493 | if (asoc) { |
3477 | assocparams.sasoc_asocmaxrxt = asoc->max_retrans; | 3494 | assocparams.sasoc_asocmaxrxt = asoc->max_retrans; |
3478 | assocparams.sasoc_peer_rwnd = asoc->peer.rwnd; | 3495 | assocparams.sasoc_peer_rwnd = asoc->peer.rwnd; |
3479 | assocparams.sasoc_local_rwnd = asoc->a_rwnd; | 3496 | assocparams.sasoc_local_rwnd = asoc->a_rwnd; |
@@ -4422,8 +4439,17 @@ static void sctp_wfree(struct sk_buff *skb) | |||
4422 | chunk = *((struct sctp_chunk **)(skb->cb)); | 4439 | chunk = *((struct sctp_chunk **)(skb->cb)); |
4423 | asoc = chunk->asoc; | 4440 | asoc = chunk->asoc; |
4424 | sk = asoc->base.sk; | 4441 | sk = asoc->base.sk; |
4425 | asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); | 4442 | asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) + |
4426 | sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk); | 4443 | sizeof(struct sk_buff) + |
4444 | sizeof(struct sctp_chunk); | ||
4445 | |||
4446 | sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk) + | ||
4447 | sizeof(struct sk_buff) + | ||
4448 | sizeof(struct sctp_chunk); | ||
4449 | |||
4450 | atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); | ||
4451 | |||
4452 | sock_wfree(skb); | ||
4427 | __sctp_write_space(asoc); | 4453 | __sctp_write_space(asoc); |
4428 | 4454 | ||
4429 | sctp_association_put(asoc); | 4455 | sctp_association_put(asoc); |