aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2007-09-26 13:35:19 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:52:44 -0400
commite356d37a096a990ea1a74c44c15640122e56110b (patch)
tree174fea2bce6bbd6d6001c7ea1b0bb914053571d0
parent9bf55cda9b2487fa7316dad3880acb0031ad3c0f (diff)
[DCCP]: Factor out common code for generating Resets
This factors code common to dccp_v{4,6}_ctl_send_reset into a separate function, and adds support for filling in the Data 1 ... Data 3 fields from RFC 4340, 5.6. It is useful to have this separate, since the following Reset codes will always be generated from the control socket rather than via dccp_send_reset: * Code 3, "No Connection", cf. 8.3.1; * Code 4, "Packet Error" (identification for Data 1 added); * Code 5, "Option Error" (identification for Data 1..3 added, will be used later); * Code 6, "Mandatory Error" (same as Option Error); * Code 7, "Connection Refused" (what on Earth is the difference to "No Connection"?); * Code 8, "Bad Service Code"; * Code 9, "Too Busy"; * Code 10, "Bad Init Cookie" (not used). Code 0 is not recommended by the RFC, the following codes would be used in dccp_send_reset() instead, since they all relate to an established DCCP connection: * Code 1, "Closed"; * Code 2, "Aborted"; * Code 11, "Aggression Penalty" (12.3). Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
-rw-r--r--net/dccp/dccp.h2
-rw-r--r--net/dccp/ipv4.c38
-rw-r--r--net/dccp/ipv6.c39
-rw-r--r--net/dccp/output.c52
4 files changed, 65 insertions, 66 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index a602d9212c64..ee97950d77d1 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -294,6 +294,8 @@ extern unsigned int dccp_poll(struct file *file, struct socket *sock,
294extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, 294extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
295 int addr_len); 295 int addr_len);
296 296
297extern struct sk_buff *dccp_ctl_make_reset(struct socket *ctl,
298 struct sk_buff *skb);
297extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); 299extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code);
298extern void dccp_send_close(struct sock *sk, const int active); 300extern void dccp_send_close(struct sock *sk, const int active);
299extern int dccp_invalid_packet(struct sk_buff *skb); 301extern int dccp_invalid_packet(struct sk_buff *skb);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 58a79c2ae55c..2312b9f4d7af 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -510,17 +510,12 @@ out:
510static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) 510static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
511{ 511{
512 int err; 512 int err;
513 struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
514 const struct iphdr *rxiph; 513 const struct iphdr *rxiph;
515 const int dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
516 sizeof(struct dccp_hdr_ext) +
517 sizeof(struct dccp_hdr_reset);
518 struct sk_buff *skb; 514 struct sk_buff *skb;
519 struct dst_entry *dst; 515 struct dst_entry *dst;
520 u64 seqno = 0;
521 516
522 /* Never send a reset in response to a reset. */ 517 /* Never send a reset in response to a reset. */
523 if (rxdh->dccph_type == DCCP_PKT_RESET) 518 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
524 return; 519 return;
525 520
526 if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) 521 if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
@@ -530,37 +525,14 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
530 if (dst == NULL) 525 if (dst == NULL)
531 return; 526 return;
532 527
533 skb = alloc_skb(dccp_v4_ctl_socket->sk->sk_prot->max_header, 528 skb = dccp_ctl_make_reset(dccp_v4_ctl_socket, rxskb);
534 GFP_ATOMIC);
535 if (skb == NULL) 529 if (skb == NULL)
536 goto out; 530 goto out;
537 531
538 /* Reserve space for headers. */
539 skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header);
540 skb->dst = dst_clone(dst);
541
542 dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len);
543
544 /* Build DCCP header and checksum it. */
545 dh->dccph_type = DCCP_PKT_RESET;
546 dh->dccph_sport = rxdh->dccph_dport;
547 dh->dccph_dport = rxdh->dccph_sport;
548 dh->dccph_doff = dccp_hdr_reset_len / 4;
549 dh->dccph_x = 1;
550 dccp_hdr_reset(skb)->dccph_reset_code =
551 DCCP_SKB_CB(rxskb)->dccpd_reset_code;
552
553 /* See "8.3.1. Abnormal Termination" in RFC 4340 */
554 if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
555 seqno = ADD48(DCCP_SKB_CB(rxskb)->dccpd_ack_seq, 1);
556
557 dccp_hdr_set_seq(dh, seqno);
558 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq);
559
560 dccp_csum_outgoing(skb);
561 rxiph = ip_hdr(rxskb); 532 rxiph = ip_hdr(rxskb);
562 dh->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr, 533 dccp_hdr(skb)->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr,
563 rxiph->daddr); 534 rxiph->daddr);
535 skb->dst = dst_clone(dst);
564 536
565 bh_lock_sock(dccp_v4_ctl_socket->sk); 537 bh_lock_sock(dccp_v4_ctl_socket->sk);
566 err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, 538 err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index d954e8319dbd..b7c0f66e2834 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -301,50 +301,23 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req)
301 301
302static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) 302static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
303{ 303{
304 struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
305 struct ipv6hdr *rxip6h; 304 struct ipv6hdr *rxip6h;
306 const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
307 sizeof(struct dccp_hdr_ext) +
308 sizeof(struct dccp_hdr_reset);
309 struct sk_buff *skb; 305 struct sk_buff *skb;
310 struct flowi fl; 306 struct flowi fl;
311 u64 seqno = 0;
312 307
313 if (rxdh->dccph_type == DCCP_PKT_RESET) 308 if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
314 return; 309 return;
315 310
316 if (!ipv6_unicast_destination(rxskb)) 311 if (!ipv6_unicast_destination(rxskb))
317 return; 312 return;
318 313
319 skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header, 314 skb = dccp_ctl_make_reset(dccp_v6_ctl_socket, rxskb);
320 GFP_ATOMIC);
321 if (skb == NULL) 315 if (skb == NULL)
322 return; 316 return;
323 317
324 skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header);
325
326 dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len);
327
328 /* Swap the send and the receive. */
329 dh->dccph_type = DCCP_PKT_RESET;
330 dh->dccph_sport = rxdh->dccph_dport;
331 dh->dccph_dport = rxdh->dccph_sport;
332 dh->dccph_doff = dccp_hdr_reset_len / 4;
333 dh->dccph_x = 1;
334 dccp_hdr_reset(skb)->dccph_reset_code =
335 DCCP_SKB_CB(rxskb)->dccpd_reset_code;
336
337 /* See "8.3.1. Abnormal Termination" in RFC 4340 */
338 if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
339 seqno = ADD48(DCCP_SKB_CB(rxskb)->dccpd_ack_seq, 1);
340
341 dccp_hdr_set_seq(dh, seqno);
342 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq);
343
344 dccp_csum_outgoing(skb);
345 rxip6h = ipv6_hdr(rxskb); 318 rxip6h = ipv6_hdr(rxskb);
346 dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr, 319 dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
347 &rxip6h->daddr); 320 &rxip6h->daddr);
348 321
349 memset(&fl, 0, sizeof(fl)); 322 memset(&fl, 0, sizeof(fl));
350 ipv6_addr_copy(&fl.fl6_dst, &rxip6h->saddr); 323 ipv6_addr_copy(&fl.fl6_dst, &rxip6h->saddr);
@@ -352,8 +325,8 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
352 325
353 fl.proto = IPPROTO_DCCP; 326 fl.proto = IPPROTO_DCCP;
354 fl.oif = inet6_iif(rxskb); 327 fl.oif = inet6_iif(rxskb);
355 fl.fl_ip_dport = dh->dccph_dport; 328 fl.fl_ip_dport = dccp_hdr(skb)->dccph_dport;
356 fl.fl_ip_sport = dh->dccph_sport; 329 fl.fl_ip_sport = dccp_hdr(skb)->dccph_sport;
357 security_skb_classify_flow(rxskb, &fl); 330 security_skb_classify_flow(rxskb, &fl);
358 331
359 /* sk = NULL, but it is safe for now. RST socket required. */ 332 /* sk = NULL, but it is safe for now. RST socket required. */
diff --git a/net/dccp/output.c b/net/dccp/output.c
index f4bde2056204..6a334ed5e9d6 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -327,6 +327,58 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
327 327
328EXPORT_SYMBOL_GPL(dccp_make_response); 328EXPORT_SYMBOL_GPL(dccp_make_response);
329 329
330/* answer offending packet in @rcv_skb with Reset from control socket @ctl */
331struct sk_buff *dccp_ctl_make_reset(struct socket *ctl, struct sk_buff *rcv_skb)
332{
333 struct dccp_hdr *rxdh = dccp_hdr(rcv_skb), *dh;
334 struct dccp_skb_cb *dcb = DCCP_SKB_CB(rcv_skb);
335 const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
336 sizeof(struct dccp_hdr_ext) +
337 sizeof(struct dccp_hdr_reset);
338 struct dccp_hdr_reset *dhr;
339 struct sk_buff *skb;
340
341 skb = alloc_skb(ctl->sk->sk_prot->max_header, GFP_ATOMIC);
342 if (skb == NULL)
343 return NULL;
344
345 skb_reserve(skb, ctl->sk->sk_prot->max_header);
346
347 /* Swap the send and the receive. */
348 dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len);
349 dh->dccph_type = DCCP_PKT_RESET;
350 dh->dccph_sport = rxdh->dccph_dport;
351 dh->dccph_dport = rxdh->dccph_sport;
352 dh->dccph_doff = dccp_hdr_reset_len / 4;
353 dh->dccph_x = 1;
354
355 dhr = dccp_hdr_reset(skb);
356 dhr->dccph_reset_code = dcb->dccpd_reset_code;
357
358 switch (dcb->dccpd_reset_code) {
359 case DCCP_RESET_CODE_PACKET_ERROR:
360 dhr->dccph_reset_data[0] = rxdh->dccph_type;
361 break;
362 case DCCP_RESET_CODE_OPTION_ERROR: /* fall through */
363 case DCCP_RESET_CODE_MANDATORY_ERROR:
364 memcpy(dhr->dccph_reset_data, dcb->dccpd_reset_data, 3);
365 break;
366 }
367 /*
368 * From RFC 4340, 8.3.1:
369 * If P.ackno exists, set R.seqno := P.ackno + 1.
370 * Else set R.seqno := 0.
371 */
372 if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
373 dccp_hdr_set_seq(dh, ADD48(dcb->dccpd_ack_seq, 1));
374 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dcb->dccpd_seq);
375
376 dccp_csum_outgoing(skb);
377 return skb;
378}
379
380EXPORT_SYMBOL_GPL(dccp_ctl_make_reset);
381
330/* send Reset on established socket, to close or abort the connection */ 382/* send Reset on established socket, to close or abort the connection */
331int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code) 383int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code)
332{ 384{