diff options
-rw-r--r-- | net/dccp/output.c | 78 |
1 files changed, 19 insertions, 59 deletions
diff --git a/net/dccp/output.c b/net/dccp/output.c index d0c9ec6494bf..f4bde2056204 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -61,6 +61,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
61 | set_ack = 0; | 61 | set_ack = 0; |
62 | /* fall through */ | 62 | /* fall through */ |
63 | case DCCP_PKT_DATAACK: | 63 | case DCCP_PKT_DATAACK: |
64 | case DCCP_PKT_RESET: | ||
64 | break; | 65 | break; |
65 | 66 | ||
66 | case DCCP_PKT_REQUEST: | 67 | case DCCP_PKT_REQUEST: |
@@ -73,8 +74,10 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
73 | /* fall through */ | 74 | /* fall through */ |
74 | default: | 75 | default: |
75 | /* | 76 | /* |
76 | * Only data packets should come through with skb->sk | 77 | * Set owner/destructor: some skbs are allocated via |
77 | * set. | 78 | * alloc_skb (e.g. when retransmission may happen). |
79 | * Only Data, DataAck, and Reset packets should come | ||
80 | * through here with skb->sk set. | ||
78 | */ | 81 | */ |
79 | WARN_ON(skb->sk); | 82 | WARN_ON(skb->sk); |
80 | skb_set_owner_w(skb, sk); | 83 | skb_set_owner_w(skb, sk); |
@@ -324,72 +327,29 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | |||
324 | 327 | ||
325 | EXPORT_SYMBOL_GPL(dccp_make_response); | 328 | EXPORT_SYMBOL_GPL(dccp_make_response); |
326 | 329 | ||
327 | static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, | 330 | /* send Reset on established socket, to close or abort the connection */ |
328 | const enum dccp_reset_codes code) | ||
329 | { | ||
330 | struct dccp_hdr *dh; | ||
331 | struct dccp_sock *dp = dccp_sk(sk); | ||
332 | const u32 dccp_header_size = sizeof(struct dccp_hdr) + | ||
333 | sizeof(struct dccp_hdr_ext) + | ||
334 | sizeof(struct dccp_hdr_reset); | ||
335 | struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1, | ||
336 | GFP_ATOMIC); | ||
337 | if (skb == NULL) | ||
338 | return NULL; | ||
339 | |||
340 | /* Reserve space for headers. */ | ||
341 | skb_reserve(skb, sk->sk_prot->max_header); | ||
342 | |||
343 | skb->dst = dst_clone(dst); | ||
344 | |||
345 | dccp_inc_seqno(&dp->dccps_gss); | ||
346 | |||
347 | DCCP_SKB_CB(skb)->dccpd_reset_code = code; | ||
348 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESET; | ||
349 | DCCP_SKB_CB(skb)->dccpd_seq = dp->dccps_gss; | ||
350 | |||
351 | if (dccp_insert_options(sk, skb)) { | ||
352 | kfree_skb(skb); | ||
353 | return NULL; | ||
354 | } | ||
355 | |||
356 | dh = dccp_zeroed_hdr(skb, dccp_header_size); | ||
357 | |||
358 | dh->dccph_sport = inet_sk(sk)->sport; | ||
359 | dh->dccph_dport = inet_sk(sk)->dport; | ||
360 | dh->dccph_doff = (dccp_header_size + | ||
361 | DCCP_SKB_CB(skb)->dccpd_opt_len) / 4; | ||
362 | dh->dccph_type = DCCP_PKT_RESET; | ||
363 | dh->dccph_x = 1; | ||
364 | dccp_hdr_set_seq(dh, dp->dccps_gss); | ||
365 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr); | ||
366 | |||
367 | dccp_hdr_reset(skb)->dccph_reset_code = code; | ||
368 | inet_csk(sk)->icsk_af_ops->send_check(sk, 0, skb); | ||
369 | |||
370 | DCCP_INC_STATS(DCCP_MIB_OUTSEGS); | ||
371 | return skb; | ||
372 | } | ||
373 | |||
374 | int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code) | 331 | int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code) |
375 | { | 332 | { |
333 | struct sk_buff *skb; | ||
376 | /* | 334 | /* |
377 | * FIXME: what if rebuild_header fails? | 335 | * FIXME: what if rebuild_header fails? |
378 | * Should we be doing a rebuild_header here? | 336 | * Should we be doing a rebuild_header here? |
379 | */ | 337 | */ |
380 | int err = inet_sk_rebuild_header(sk); | 338 | int err = inet_sk_rebuild_header(sk); |
381 | 339 | ||
382 | if (err == 0) { | 340 | if (err != 0) |
383 | struct sk_buff *skb = dccp_make_reset(sk, sk->sk_dst_cache, | 341 | return err; |
384 | code); | 342 | |
385 | if (skb != NULL) { | 343 | skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1, GFP_ATOMIC); |
386 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | 344 | if (skb == NULL) |
387 | err = inet_csk(sk)->icsk_af_ops->queue_xmit(skb, 0); | 345 | return -ENOBUFS; |
388 | return net_xmit_eval(err); | 346 | |
389 | } | 347 | /* Reserve space for headers and prepare control bits. */ |
390 | } | 348 | skb_reserve(skb, sk->sk_prot->max_header); |
349 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESET; | ||
350 | DCCP_SKB_CB(skb)->dccpd_reset_code = code; | ||
391 | 351 | ||
392 | return err; | 352 | return dccp_transmit_skb(sk, skb); |
393 | } | 353 | } |
394 | 354 | ||
395 | /* | 355 | /* |