diff options
-rw-r--r-- | net/dccp/ipv4.c | 266 |
1 files changed, 132 insertions, 134 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 8dd9f5aa27a2..ed6202652bcc 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -193,37 +193,6 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk, | |||
193 | } /* else let the usual retransmit timer handle it */ | 193 | } /* else let the usual retransmit timer handle it */ |
194 | } | 194 | } |
195 | 195 | ||
196 | static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, | ||
197 | struct dst_entry *dst) | ||
198 | { | ||
199 | int err = -1; | ||
200 | struct sk_buff *skb; | ||
201 | |||
202 | /* First, grab a route. */ | ||
203 | |||
204 | if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) | ||
205 | goto out; | ||
206 | |||
207 | skb = dccp_make_response(sk, dst, req); | ||
208 | if (skb != NULL) { | ||
209 | const struct inet_request_sock *ireq = inet_rsk(req); | ||
210 | struct dccp_hdr *dh = dccp_hdr(skb); | ||
211 | |||
212 | dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr, | ||
213 | ireq->rmt_addr); | ||
214 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | ||
215 | err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, | ||
216 | ireq->rmt_addr, | ||
217 | ireq->opt); | ||
218 | if (err == NET_XMIT_CN) | ||
219 | err = 0; | ||
220 | } | ||
221 | |||
222 | out: | ||
223 | dst_release(dst); | ||
224 | return err; | ||
225 | } | ||
226 | |||
227 | /* | 196 | /* |
228 | * This routine is called by the ICMP module when it gets some sort of error | 197 | * This routine is called by the ICMP module when it gets some sort of error |
229 | * condition. If err < 0 then the socket should be closed and the error | 198 | * condition. If err < 0 then the socket should be closed and the error |
@@ -400,95 +369,6 @@ static inline u64 dccp_v4_init_sequence(const struct sock *sk, | |||
400 | dccp_hdr(skb)->dccph_sport); | 369 | dccp_hdr(skb)->dccph_sport); |
401 | } | 370 | } |
402 | 371 | ||
403 | static struct request_sock_ops dccp_request_sock_ops; | ||
404 | |||
405 | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | ||
406 | { | ||
407 | struct inet_request_sock *ireq; | ||
408 | struct dccp_sock dp; | ||
409 | struct request_sock *req; | ||
410 | struct dccp_request_sock *dreq; | ||
411 | const __be32 saddr = skb->nh.iph->saddr; | ||
412 | const __be32 daddr = skb->nh.iph->daddr; | ||
413 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; | ||
414 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
415 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | ||
416 | |||
417 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ | ||
418 | if (((struct rtable *)skb->dst)->rt_flags & | ||
419 | (RTCF_BROADCAST | RTCF_MULTICAST)) { | ||
420 | reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
421 | goto drop; | ||
422 | } | ||
423 | |||
424 | if (dccp_bad_service_code(sk, service)) { | ||
425 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | ||
426 | goto drop; | ||
427 | } | ||
428 | /* | ||
429 | * TW buckets are converted to open requests without | ||
430 | * limitations, they conserve resources and peer is | ||
431 | * evidently real one. | ||
432 | */ | ||
433 | if (inet_csk_reqsk_queue_is_full(sk)) | ||
434 | goto drop; | ||
435 | |||
436 | /* | ||
437 | * Accept backlog is full. If we have already queued enough | ||
438 | * of warm entries in syn queue, drop request. It is better than | ||
439 | * clogging syn queue with openreqs with exponentially increasing | ||
440 | * timeout. | ||
441 | */ | ||
442 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) | ||
443 | goto drop; | ||
444 | |||
445 | req = reqsk_alloc(&dccp_request_sock_ops); | ||
446 | if (req == NULL) | ||
447 | goto drop; | ||
448 | |||
449 | if (dccp_parse_options(sk, skb)) | ||
450 | goto drop_and_free; | ||
451 | |||
452 | dccp_openreq_init(req, &dp, skb); | ||
453 | |||
454 | if (security_inet_conn_request(sk, skb, req)) | ||
455 | goto drop_and_free; | ||
456 | |||
457 | ireq = inet_rsk(req); | ||
458 | ireq->loc_addr = daddr; | ||
459 | ireq->rmt_addr = saddr; | ||
460 | req->rcv_wnd = dccp_feat_default_sequence_window; | ||
461 | ireq->opt = NULL; | ||
462 | |||
463 | /* | ||
464 | * Step 3: Process LISTEN state | ||
465 | * | ||
466 | * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie | ||
467 | * | ||
468 | * In fact we defer setting S.GSR, S.SWL, S.SWH to | ||
469 | * dccp_create_openreq_child. | ||
470 | */ | ||
471 | dreq = dccp_rsk(req); | ||
472 | dreq->dreq_isr = dcb->dccpd_seq; | ||
473 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); | ||
474 | dreq->dreq_service = service; | ||
475 | |||
476 | if (dccp_v4_send_response(sk, req, NULL)) | ||
477 | goto drop_and_free; | ||
478 | |||
479 | inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); | ||
480 | return 0; | ||
481 | |||
482 | drop_and_free: | ||
483 | reqsk_free(req); | ||
484 | drop: | ||
485 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | ||
486 | dcb->dccpd_reset_code = reset_code; | ||
487 | return -1; | ||
488 | } | ||
489 | |||
490 | EXPORT_SYMBOL_GPL(dccp_v4_conn_request); | ||
491 | |||
492 | /* | 372 | /* |
493 | * The three way handshake has completed - we got a valid ACK or DATAACK - | 373 | * The three way handshake has completed - we got a valid ACK or DATAACK - |
494 | * now create the new socket. | 374 | * now create the new socket. |
@@ -640,6 +520,37 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, | |||
640 | return &rt->u.dst; | 520 | return &rt->u.dst; |
641 | } | 521 | } |
642 | 522 | ||
523 | static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, | ||
524 | struct dst_entry *dst) | ||
525 | { | ||
526 | int err = -1; | ||
527 | struct sk_buff *skb; | ||
528 | |||
529 | /* First, grab a route. */ | ||
530 | |||
531 | if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) | ||
532 | goto out; | ||
533 | |||
534 | skb = dccp_make_response(sk, dst, req); | ||
535 | if (skb != NULL) { | ||
536 | const struct inet_request_sock *ireq = inet_rsk(req); | ||
537 | struct dccp_hdr *dh = dccp_hdr(skb); | ||
538 | |||
539 | dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr, | ||
540 | ireq->rmt_addr); | ||
541 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | ||
542 | err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, | ||
543 | ireq->rmt_addr, | ||
544 | ireq->opt); | ||
545 | if (err == NET_XMIT_CN) | ||
546 | err = 0; | ||
547 | } | ||
548 | |||
549 | out: | ||
550 | dst_release(dst); | ||
551 | return err; | ||
552 | } | ||
553 | |||
643 | static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) | 554 | static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) |
644 | { | 555 | { |
645 | int err; | 556 | int err; |
@@ -708,6 +619,107 @@ out: | |||
708 | dst_release(dst); | 619 | dst_release(dst); |
709 | } | 620 | } |
710 | 621 | ||
622 | static void dccp_v4_reqsk_destructor(struct request_sock *req) | ||
623 | { | ||
624 | kfree(inet_rsk(req)->opt); | ||
625 | } | ||
626 | |||
627 | static struct request_sock_ops dccp_request_sock_ops __read_mostly = { | ||
628 | .family = PF_INET, | ||
629 | .obj_size = sizeof(struct dccp_request_sock), | ||
630 | .rtx_syn_ack = dccp_v4_send_response, | ||
631 | .send_ack = dccp_reqsk_send_ack, | ||
632 | .destructor = dccp_v4_reqsk_destructor, | ||
633 | .send_reset = dccp_v4_ctl_send_reset, | ||
634 | }; | ||
635 | |||
636 | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | ||
637 | { | ||
638 | struct inet_request_sock *ireq; | ||
639 | struct dccp_sock dp; | ||
640 | struct request_sock *req; | ||
641 | struct dccp_request_sock *dreq; | ||
642 | const __be32 saddr = skb->nh.iph->saddr; | ||
643 | const __be32 daddr = skb->nh.iph->daddr; | ||
644 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; | ||
645 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
646 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | ||
647 | |||
648 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ | ||
649 | if (((struct rtable *)skb->dst)->rt_flags & | ||
650 | (RTCF_BROADCAST | RTCF_MULTICAST)) { | ||
651 | reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
652 | goto drop; | ||
653 | } | ||
654 | |||
655 | if (dccp_bad_service_code(sk, service)) { | ||
656 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | ||
657 | goto drop; | ||
658 | } | ||
659 | /* | ||
660 | * TW buckets are converted to open requests without | ||
661 | * limitations, they conserve resources and peer is | ||
662 | * evidently real one. | ||
663 | */ | ||
664 | if (inet_csk_reqsk_queue_is_full(sk)) | ||
665 | goto drop; | ||
666 | |||
667 | /* | ||
668 | * Accept backlog is full. If we have already queued enough | ||
669 | * of warm entries in syn queue, drop request. It is better than | ||
670 | * clogging syn queue with openreqs with exponentially increasing | ||
671 | * timeout. | ||
672 | */ | ||
673 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) | ||
674 | goto drop; | ||
675 | |||
676 | req = reqsk_alloc(&dccp_request_sock_ops); | ||
677 | if (req == NULL) | ||
678 | goto drop; | ||
679 | |||
680 | if (dccp_parse_options(sk, skb)) | ||
681 | goto drop_and_free; | ||
682 | |||
683 | dccp_openreq_init(req, &dp, skb); | ||
684 | |||
685 | if (security_inet_conn_request(sk, skb, req)) | ||
686 | goto drop_and_free; | ||
687 | |||
688 | ireq = inet_rsk(req); | ||
689 | ireq->loc_addr = daddr; | ||
690 | ireq->rmt_addr = saddr; | ||
691 | req->rcv_wnd = dccp_feat_default_sequence_window; | ||
692 | ireq->opt = NULL; | ||
693 | |||
694 | /* | ||
695 | * Step 3: Process LISTEN state | ||
696 | * | ||
697 | * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie | ||
698 | * | ||
699 | * In fact we defer setting S.GSR, S.SWL, S.SWH to | ||
700 | * dccp_create_openreq_child. | ||
701 | */ | ||
702 | dreq = dccp_rsk(req); | ||
703 | dreq->dreq_isr = dcb->dccpd_seq; | ||
704 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); | ||
705 | dreq->dreq_service = service; | ||
706 | |||
707 | if (dccp_v4_send_response(sk, req, NULL)) | ||
708 | goto drop_and_free; | ||
709 | |||
710 | inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); | ||
711 | return 0; | ||
712 | |||
713 | drop_and_free: | ||
714 | reqsk_free(req); | ||
715 | drop: | ||
716 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | ||
717 | dcb->dccpd_reset_code = reset_code; | ||
718 | return -1; | ||
719 | } | ||
720 | |||
721 | EXPORT_SYMBOL_GPL(dccp_v4_conn_request); | ||
722 | |||
711 | int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) | 723 | int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) |
712 | { | 724 | { |
713 | struct dccp_hdr *dh = dccp_hdr(skb); | 725 | struct dccp_hdr *dh = dccp_hdr(skb); |
@@ -959,20 +971,6 @@ static int dccp_v4_init_sock(struct sock *sk) | |||
959 | return err; | 971 | return err; |
960 | } | 972 | } |
961 | 973 | ||
962 | static void dccp_v4_reqsk_destructor(struct request_sock *req) | ||
963 | { | ||
964 | kfree(inet_rsk(req)->opt); | ||
965 | } | ||
966 | |||
967 | static struct request_sock_ops dccp_request_sock_ops __read_mostly = { | ||
968 | .family = PF_INET, | ||
969 | .obj_size = sizeof(struct dccp_request_sock), | ||
970 | .rtx_syn_ack = dccp_v4_send_response, | ||
971 | .send_ack = dccp_reqsk_send_ack, | ||
972 | .destructor = dccp_v4_reqsk_destructor, | ||
973 | .send_reset = dccp_v4_ctl_send_reset, | ||
974 | }; | ||
975 | |||
976 | static struct timewait_sock_ops dccp_timewait_sock_ops = { | 974 | static struct timewait_sock_ops dccp_timewait_sock_ops = { |
977 | .twsk_obj_size = sizeof(struct inet_timewait_sock), | 975 | .twsk_obj_size = sizeof(struct inet_timewait_sock), |
978 | }; | 976 | }; |