diff options
Diffstat (limited to 'net/dccp/ipv6.c')
-rw-r--r-- | net/dccp/ipv6.c | 613 |
1 files changed, 292 insertions, 321 deletions
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index fc4242c0767c..c7aaa2574f52 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -36,13 +36,6 @@ | |||
36 | /* Socket used for sending RSTs and ACKs */ | 36 | /* Socket used for sending RSTs and ACKs */ |
37 | static struct socket *dccp_v6_ctl_socket; | 37 | static struct socket *dccp_v6_ctl_socket; |
38 | 38 | ||
39 | static void dccp_v6_ctl_send_reset(struct sk_buff *skb); | ||
40 | static void dccp_v6_reqsk_send_ack(struct sk_buff *skb, | ||
41 | struct request_sock *req); | ||
42 | static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb); | ||
43 | |||
44 | static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); | ||
45 | |||
46 | static struct inet_connection_sock_af_ops dccp_ipv6_mapped; | 39 | static struct inet_connection_sock_af_ops dccp_ipv6_mapped; |
47 | static struct inet_connection_sock_af_ops dccp_ipv6_af_ops; | 40 | static struct inet_connection_sock_af_ops dccp_ipv6_af_ops; |
48 | 41 | ||
@@ -65,205 +58,37 @@ static void dccp_v6_hash(struct sock *sk) | |||
65 | } | 58 | } |
66 | } | 59 | } |
67 | 60 | ||
68 | static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len, | 61 | /* add pseudo-header to DCCP checksum stored in skb->csum */ |
69 | struct in6_addr *saddr, | 62 | static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb, |
70 | struct in6_addr *daddr, | 63 | struct in6_addr *saddr, |
71 | unsigned long base) | 64 | struct in6_addr *daddr) |
72 | { | 65 | { |
73 | return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base); | 66 | return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum); |
74 | } | 67 | } |
75 | 68 | ||
76 | static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb) | 69 | static inline void dccp_v6_send_check(struct sock *sk, int unused_value, |
70 | struct sk_buff *skb) | ||
77 | { | 71 | { |
78 | const struct dccp_hdr *dh = dccp_hdr(skb); | 72 | struct ipv6_pinfo *np = inet6_sk(sk); |
79 | 73 | struct dccp_hdr *dh = dccp_hdr(skb); | |
80 | if (skb->protocol == htons(ETH_P_IPV6)) | ||
81 | return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32, | ||
82 | skb->nh.ipv6h->saddr.s6_addr32, | ||
83 | dh->dccph_dport, | ||
84 | dh->dccph_sport); | ||
85 | 74 | ||
86 | return secure_dccp_sequence_number(skb->nh.iph->daddr, | 75 | dccp_csum_outgoing(skb); |
87 | skb->nh.iph->saddr, | 76 | dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr); |
88 | dh->dccph_dport, | ||
89 | dh->dccph_sport); | ||
90 | } | 77 | } |
91 | 78 | ||
92 | static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | 79 | static inline __u32 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, |
93 | int addr_len) | 80 | __be16 sport, __be16 dport ) |
94 | { | 81 | { |
95 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr; | 82 | return secure_tcpv6_sequence_number(saddr, daddr, sport, dport); |
96 | struct inet_connection_sock *icsk = inet_csk(sk); | 83 | } |
97 | struct inet_sock *inet = inet_sk(sk); | ||
98 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
99 | struct dccp_sock *dp = dccp_sk(sk); | ||
100 | struct in6_addr *saddr = NULL, *final_p = NULL, final; | ||
101 | struct flowi fl; | ||
102 | struct dst_entry *dst; | ||
103 | int addr_type; | ||
104 | int err; | ||
105 | |||
106 | dp->dccps_role = DCCP_ROLE_CLIENT; | ||
107 | |||
108 | if (addr_len < SIN6_LEN_RFC2133) | ||
109 | return -EINVAL; | ||
110 | |||
111 | if (usin->sin6_family != AF_INET6) | ||
112 | return -EAFNOSUPPORT; | ||
113 | |||
114 | memset(&fl, 0, sizeof(fl)); | ||
115 | |||
116 | if (np->sndflow) { | ||
117 | fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK; | ||
118 | IP6_ECN_flow_init(fl.fl6_flowlabel); | ||
119 | if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) { | ||
120 | struct ip6_flowlabel *flowlabel; | ||
121 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | ||
122 | if (flowlabel == NULL) | ||
123 | return -EINVAL; | ||
124 | ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst); | ||
125 | fl6_sock_release(flowlabel); | ||
126 | } | ||
127 | } | ||
128 | /* | ||
129 | * connect() to INADDR_ANY means loopback (BSD'ism). | ||
130 | */ | ||
131 | if (ipv6_addr_any(&usin->sin6_addr)) | ||
132 | usin->sin6_addr.s6_addr[15] = 1; | ||
133 | |||
134 | addr_type = ipv6_addr_type(&usin->sin6_addr); | ||
135 | |||
136 | if (addr_type & IPV6_ADDR_MULTICAST) | ||
137 | return -ENETUNREACH; | ||
138 | |||
139 | if (addr_type & IPV6_ADDR_LINKLOCAL) { | ||
140 | if (addr_len >= sizeof(struct sockaddr_in6) && | ||
141 | usin->sin6_scope_id) { | ||
142 | /* If interface is set while binding, indices | ||
143 | * must coincide. | ||
144 | */ | ||
145 | if (sk->sk_bound_dev_if && | ||
146 | sk->sk_bound_dev_if != usin->sin6_scope_id) | ||
147 | return -EINVAL; | ||
148 | |||
149 | sk->sk_bound_dev_if = usin->sin6_scope_id; | ||
150 | } | ||
151 | |||
152 | /* Connect to link-local address requires an interface */ | ||
153 | if (!sk->sk_bound_dev_if) | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | ipv6_addr_copy(&np->daddr, &usin->sin6_addr); | ||
158 | np->flow_label = fl.fl6_flowlabel; | ||
159 | |||
160 | /* | ||
161 | * DCCP over IPv4 | ||
162 | */ | ||
163 | if (addr_type == IPV6_ADDR_MAPPED) { | ||
164 | u32 exthdrlen = icsk->icsk_ext_hdr_len; | ||
165 | struct sockaddr_in sin; | ||
166 | |||
167 | SOCK_DEBUG(sk, "connect: ipv4 mapped\n"); | ||
168 | |||
169 | if (__ipv6_only_sock(sk)) | ||
170 | return -ENETUNREACH; | ||
171 | |||
172 | sin.sin_family = AF_INET; | ||
173 | sin.sin_port = usin->sin6_port; | ||
174 | sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; | ||
175 | |||
176 | icsk->icsk_af_ops = &dccp_ipv6_mapped; | ||
177 | sk->sk_backlog_rcv = dccp_v4_do_rcv; | ||
178 | |||
179 | err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); | ||
180 | if (err) { | ||
181 | icsk->icsk_ext_hdr_len = exthdrlen; | ||
182 | icsk->icsk_af_ops = &dccp_ipv6_af_ops; | ||
183 | sk->sk_backlog_rcv = dccp_v6_do_rcv; | ||
184 | goto failure; | ||
185 | } else { | ||
186 | ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF), | ||
187 | inet->saddr); | ||
188 | ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF), | ||
189 | inet->rcv_saddr); | ||
190 | } | ||
191 | |||
192 | return err; | ||
193 | } | ||
194 | |||
195 | if (!ipv6_addr_any(&np->rcv_saddr)) | ||
196 | saddr = &np->rcv_saddr; | ||
197 | |||
198 | fl.proto = IPPROTO_DCCP; | ||
199 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | ||
200 | ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr); | ||
201 | fl.oif = sk->sk_bound_dev_if; | ||
202 | fl.fl_ip_dport = usin->sin6_port; | ||
203 | fl.fl_ip_sport = inet->sport; | ||
204 | security_sk_classify_flow(sk, &fl); | ||
205 | |||
206 | if (np->opt != NULL && np->opt->srcrt != NULL) { | ||
207 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | ||
208 | |||
209 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
210 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
211 | final_p = &final; | ||
212 | } | ||
213 | |||
214 | err = ip6_dst_lookup(sk, &dst, &fl); | ||
215 | if (err) | ||
216 | goto failure; | ||
217 | |||
218 | if (final_p) | ||
219 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
220 | |||
221 | err = xfrm_lookup(&dst, &fl, sk, 0); | ||
222 | if (err < 0) | ||
223 | goto failure; | ||
224 | |||
225 | if (saddr == NULL) { | ||
226 | saddr = &fl.fl6_src; | ||
227 | ipv6_addr_copy(&np->rcv_saddr, saddr); | ||
228 | } | ||
229 | |||
230 | /* set the source address */ | ||
231 | ipv6_addr_copy(&np->saddr, saddr); | ||
232 | inet->rcv_saddr = LOOPBACK4_IPV6; | ||
233 | |||
234 | __ip6_dst_store(sk, dst, NULL, NULL); | ||
235 | |||
236 | icsk->icsk_ext_hdr_len = 0; | ||
237 | if (np->opt != NULL) | ||
238 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + | ||
239 | np->opt->opt_nflen); | ||
240 | |||
241 | inet->dport = usin->sin6_port; | ||
242 | |||
243 | dccp_set_state(sk, DCCP_REQUESTING); | ||
244 | err = inet6_hash_connect(&dccp_death_row, sk); | ||
245 | if (err) | ||
246 | goto late_failure; | ||
247 | /* FIXME */ | ||
248 | #if 0 | ||
249 | dp->dccps_gar = secure_dccp_v6_sequence_number(np->saddr.s6_addr32, | ||
250 | np->daddr.s6_addr32, | ||
251 | inet->sport, | ||
252 | inet->dport); | ||
253 | #endif | ||
254 | err = dccp_connect(sk); | ||
255 | if (err) | ||
256 | goto late_failure; | ||
257 | 84 | ||
258 | return 0; | 85 | static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb) |
86 | { | ||
87 | return secure_dccpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32, | ||
88 | skb->nh.ipv6h->saddr.s6_addr32, | ||
89 | dccp_hdr(skb)->dccph_dport, | ||
90 | dccp_hdr(skb)->dccph_sport ); | ||
259 | 91 | ||
260 | late_failure: | ||
261 | dccp_set_state(sk, DCCP_CLOSED); | ||
262 | __sk_dst_reset(sk); | ||
263 | failure: | ||
264 | inet->dport = 0; | ||
265 | sk->sk_route_caps = 0; | ||
266 | return err; | ||
267 | } | 92 | } |
268 | 93 | ||
269 | static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 94 | static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
@@ -464,16 +289,12 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | |||
464 | if (skb != NULL) { | 289 | if (skb != NULL) { |
465 | struct dccp_hdr *dh = dccp_hdr(skb); | 290 | struct dccp_hdr *dh = dccp_hdr(skb); |
466 | 291 | ||
467 | dh->dccph_checksum = dccp_v6_check(dh, skb->len, | 292 | dh->dccph_checksum = dccp_v6_csum_finish(skb, |
468 | &ireq6->loc_addr, | 293 | &ireq6->loc_addr, |
469 | &ireq6->rmt_addr, | 294 | &ireq6->rmt_addr); |
470 | csum_partial((char *)dh, | ||
471 | skb->len, | ||
472 | skb->csum)); | ||
473 | ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); | 295 | ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); |
474 | err = ip6_xmit(sk, skb, &fl, opt, 0); | 296 | err = ip6_xmit(sk, skb, &fl, opt, 0); |
475 | if (err == NET_XMIT_CN) | 297 | err = net_xmit_eval(err); |
476 | err = 0; | ||
477 | } | 298 | } |
478 | 299 | ||
479 | done: | 300 | done: |
@@ -489,32 +310,7 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req) | |||
489 | kfree_skb(inet6_rsk(req)->pktopts); | 310 | kfree_skb(inet6_rsk(req)->pktopts); |
490 | } | 311 | } |
491 | 312 | ||
492 | static struct request_sock_ops dccp6_request_sock_ops = { | 313 | static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) |
493 | .family = AF_INET6, | ||
494 | .obj_size = sizeof(struct dccp6_request_sock), | ||
495 | .rtx_syn_ack = dccp_v6_send_response, | ||
496 | .send_ack = dccp_v6_reqsk_send_ack, | ||
497 | .destructor = dccp_v6_reqsk_destructor, | ||
498 | .send_reset = dccp_v6_ctl_send_reset, | ||
499 | }; | ||
500 | |||
501 | static struct timewait_sock_ops dccp6_timewait_sock_ops = { | ||
502 | .twsk_obj_size = sizeof(struct dccp6_timewait_sock), | ||
503 | }; | ||
504 | |||
505 | static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | ||
506 | { | ||
507 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
508 | struct dccp_hdr *dh = dccp_hdr(skb); | ||
509 | |||
510 | dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr, | ||
511 | len, IPPROTO_DCCP, | ||
512 | csum_partial((char *)dh, | ||
513 | dh->dccph_doff << 2, | ||
514 | skb->csum)); | ||
515 | } | ||
516 | |||
517 | static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | ||
518 | { | 314 | { |
519 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; | 315 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; |
520 | const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) + | 316 | const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) + |
@@ -522,7 +318,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
522 | sizeof(struct dccp_hdr_reset); | 318 | sizeof(struct dccp_hdr_reset); |
523 | struct sk_buff *skb; | 319 | struct sk_buff *skb; |
524 | struct flowi fl; | 320 | struct flowi fl; |
525 | u64 seqno; | 321 | u64 seqno = 0; |
526 | 322 | ||
527 | if (rxdh->dccph_type == DCCP_PKT_RESET) | 323 | if (rxdh->dccph_type == DCCP_PKT_RESET) |
528 | return; | 324 | return; |
@@ -537,9 +333,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
537 | 333 | ||
538 | skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); | 334 | skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); |
539 | 335 | ||
540 | skb->h.raw = skb_push(skb, dccp_hdr_reset_len); | 336 | dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); |
541 | dh = dccp_hdr(skb); | ||
542 | memset(dh, 0, dccp_hdr_reset_len); | ||
543 | 337 | ||
544 | /* Swap the send and the receive. */ | 338 | /* Swap the send and the receive. */ |
545 | dh->dccph_type = DCCP_PKT_RESET; | 339 | dh->dccph_type = DCCP_PKT_RESET; |
@@ -551,20 +345,20 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
551 | DCCP_SKB_CB(rxskb)->dccpd_reset_code; | 345 | DCCP_SKB_CB(rxskb)->dccpd_reset_code; |
552 | 346 | ||
553 | /* See "8.3.1. Abnormal Termination" in RFC 4340 */ | 347 | /* See "8.3.1. Abnormal Termination" in RFC 4340 */ |
554 | seqno = 0; | ||
555 | if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) | 348 | if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) |
556 | dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1); | 349 | dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1); |
557 | 350 | ||
558 | dccp_hdr_set_seq(dh, seqno); | 351 | dccp_hdr_set_seq(dh, seqno); |
559 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), | 352 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); |
560 | DCCP_SKB_CB(rxskb)->dccpd_seq); | 353 | |
354 | dccp_csum_outgoing(skb); | ||
355 | dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr, | ||
356 | &rxskb->nh.ipv6h->daddr); | ||
561 | 357 | ||
562 | memset(&fl, 0, sizeof(fl)); | 358 | memset(&fl, 0, sizeof(fl)); |
563 | ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr); | 359 | ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr); |
564 | ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr); | 360 | ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr); |
565 | dh->dccph_checksum = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst, | 361 | |
566 | sizeof(*dh), IPPROTO_DCCP, | ||
567 | skb->csum); | ||
568 | fl.proto = IPPROTO_DCCP; | 362 | fl.proto = IPPROTO_DCCP; |
569 | fl.oif = inet6_iif(rxskb); | 363 | fl.oif = inet6_iif(rxskb); |
570 | fl.fl_ip_dport = dh->dccph_dport; | 364 | fl.fl_ip_dport = dh->dccph_dport; |
@@ -584,60 +378,14 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
584 | kfree_skb(skb); | 378 | kfree_skb(skb); |
585 | } | 379 | } |
586 | 380 | ||
587 | static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb, | 381 | static struct request_sock_ops dccp6_request_sock_ops = { |
588 | struct request_sock *req) | 382 | .family = AF_INET6, |
589 | { | 383 | .obj_size = sizeof(struct dccp6_request_sock), |
590 | struct flowi fl; | 384 | .rtx_syn_ack = dccp_v6_send_response, |
591 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; | 385 | .send_ack = dccp_reqsk_send_ack, |
592 | const u32 dccp_hdr_ack_len = sizeof(struct dccp_hdr) + | 386 | .destructor = dccp_v6_reqsk_destructor, |
593 | sizeof(struct dccp_hdr_ext) + | 387 | .send_reset = dccp_v6_ctl_send_reset, |
594 | sizeof(struct dccp_hdr_ack_bits); | 388 | }; |
595 | struct sk_buff *skb; | ||
596 | |||
597 | skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header, | ||
598 | GFP_ATOMIC); | ||
599 | if (skb == NULL) | ||
600 | return; | ||
601 | |||
602 | skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); | ||
603 | |||
604 | skb->h.raw = skb_push(skb, dccp_hdr_ack_len); | ||
605 | dh = dccp_hdr(skb); | ||
606 | memset(dh, 0, dccp_hdr_ack_len); | ||
607 | |||
608 | /* Build DCCP header and checksum it. */ | ||
609 | dh->dccph_type = DCCP_PKT_ACK; | ||
610 | dh->dccph_sport = rxdh->dccph_dport; | ||
611 | dh->dccph_dport = rxdh->dccph_sport; | ||
612 | dh->dccph_doff = dccp_hdr_ack_len / 4; | ||
613 | dh->dccph_x = 1; | ||
614 | |||
615 | dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq); | ||
616 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), | ||
617 | DCCP_SKB_CB(rxskb)->dccpd_seq); | ||
618 | |||
619 | memset(&fl, 0, sizeof(fl)); | ||
620 | ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr); | ||
621 | ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr); | ||
622 | |||
623 | /* FIXME: calculate checksum, IPv4 also should... */ | ||
624 | |||
625 | fl.proto = IPPROTO_DCCP; | ||
626 | fl.oif = inet6_iif(rxskb); | ||
627 | fl.fl_ip_dport = dh->dccph_dport; | ||
628 | fl.fl_ip_sport = dh->dccph_sport; | ||
629 | security_req_classify_flow(req, &fl); | ||
630 | |||
631 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { | ||
632 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { | ||
633 | ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0); | ||
634 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | ||
635 | return; | ||
636 | } | ||
637 | } | ||
638 | |||
639 | kfree_skb(skb); | ||
640 | } | ||
641 | 389 | ||
642 | static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | 390 | static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) |
643 | { | 391 | { |
@@ -672,7 +420,6 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | |||
672 | 420 | ||
673 | static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | 421 | static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) |
674 | { | 422 | { |
675 | struct dccp_sock dp; | ||
676 | struct request_sock *req; | 423 | struct request_sock *req; |
677 | struct dccp_request_sock *dreq; | 424 | struct dccp_request_sock *dreq; |
678 | struct inet6_request_sock *ireq6; | 425 | struct inet6_request_sock *ireq6; |
@@ -704,9 +451,10 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
704 | if (req == NULL) | 451 | if (req == NULL) |
705 | goto drop; | 452 | goto drop; |
706 | 453 | ||
707 | /* FIXME: process options */ | 454 | if (dccp_parse_options(sk, skb)) |
455 | goto drop_and_free; | ||
708 | 456 | ||
709 | dccp_openreq_init(req, &dp, skb); | 457 | dccp_reqsk_init(req, skb); |
710 | 458 | ||
711 | if (security_inet_conn_request(sk, skb, req)) | 459 | if (security_inet_conn_request(sk, skb, req)) |
712 | goto drop_and_free; | 460 | goto drop_and_free; |
@@ -714,7 +462,6 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
714 | ireq6 = inet6_rsk(req); | 462 | ireq6 = inet6_rsk(req); |
715 | ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr); | 463 | ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr); |
716 | ipv6_addr_copy(&ireq6->loc_addr, &skb->nh.ipv6h->daddr); | 464 | ipv6_addr_copy(&ireq6->loc_addr, &skb->nh.ipv6h->daddr); |
717 | req->rcv_wnd = dccp_feat_default_sequence_window; | ||
718 | ireq6->pktopts = NULL; | 465 | ireq6->pktopts = NULL; |
719 | 466 | ||
720 | if (ipv6_opt_accepted(sk, skb) || | 467 | if (ipv6_opt_accepted(sk, skb) || |
@@ -733,14 +480,14 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
733 | /* | 480 | /* |
734 | * Step 3: Process LISTEN state | 481 | * Step 3: Process LISTEN state |
735 | * | 482 | * |
736 | * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie | 483 | * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie |
737 | * | 484 | * |
738 | * In fact we defer setting S.GSR, S.SWL, S.SWH to | 485 | * In fact we defer setting S.GSR, S.SWL, S.SWH to |
739 | * dccp_create_openreq_child. | 486 | * dccp_create_openreq_child. |
740 | */ | 487 | */ |
741 | dreq = dccp_rsk(req); | 488 | dreq = dccp_rsk(req); |
742 | dreq->dreq_isr = dcb->dccpd_seq; | 489 | dreq->dreq_isr = dcb->dccpd_seq; |
743 | dreq->dreq_iss = dccp_v6_init_sequence(sk, skb); | 490 | dreq->dreq_iss = dccp_v6_init_sequence(skb); |
744 | dreq->dreq_service = service; | 491 | dreq->dreq_service = service; |
745 | 492 | ||
746 | if (dccp_v6_send_response(sk, req, NULL)) | 493 | if (dccp_v6_send_response(sk, req, NULL)) |
@@ -990,18 +737,46 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
990 | --ANK (980728) | 737 | --ANK (980728) |
991 | */ | 738 | */ |
992 | if (np->rxopt.all) | 739 | if (np->rxopt.all) |
740 | /* | ||
741 | * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below | ||
742 | * (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example. | ||
743 | */ | ||
993 | opt_skb = skb_clone(skb, GFP_ATOMIC); | 744 | opt_skb = skb_clone(skb, GFP_ATOMIC); |
994 | 745 | ||
995 | if (sk->sk_state == DCCP_OPEN) { /* Fast path */ | 746 | if (sk->sk_state == DCCP_OPEN) { /* Fast path */ |
996 | if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len)) | 747 | if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len)) |
997 | goto reset; | 748 | goto reset; |
998 | if (opt_skb) { | 749 | if (opt_skb) { |
999 | /* This is where we would goto ipv6_pktoptions. */ | 750 | /* XXX This is where we would goto ipv6_pktoptions. */ |
1000 | __kfree_skb(opt_skb); | 751 | __kfree_skb(opt_skb); |
1001 | } | 752 | } |
1002 | return 0; | 753 | return 0; |
1003 | } | 754 | } |
1004 | 755 | ||
756 | /* | ||
757 | * Step 3: Process LISTEN state | ||
758 | * If S.state == LISTEN, | ||
759 | * If P.type == Request or P contains a valid Init Cookie option, | ||
760 | * (* Must scan the packet's options to check for Init | ||
761 | * Cookies. Only Init Cookies are processed here, | ||
762 | * however; other options are processed in Step 8. This | ||
763 | * scan need only be performed if the endpoint uses Init | ||
764 | * Cookies *) | ||
765 | * (* Generate a new socket and switch to that socket *) | ||
766 | * Set S := new socket for this port pair | ||
767 | * S.state = RESPOND | ||
768 | * Choose S.ISS (initial seqno) or set from Init Cookies | ||
769 | * Initialize S.GAR := S.ISS | ||
770 | * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies | ||
771 | * Continue with S.state == RESPOND | ||
772 | * (* A Response packet will be generated in Step 11 *) | ||
773 | * Otherwise, | ||
774 | * Generate Reset(No Connection) unless P.type == Reset | ||
775 | * Drop packet and return | ||
776 | * | ||
777 | * NOTE: the check for the packet types is done in | ||
778 | * dccp_rcv_state_process | ||
779 | */ | ||
1005 | if (sk->sk_state == DCCP_LISTEN) { | 780 | if (sk->sk_state == DCCP_LISTEN) { |
1006 | struct sock *nsk = dccp_v6_hnd_req(sk, skb); | 781 | struct sock *nsk = dccp_v6_hnd_req(sk, skb); |
1007 | 782 | ||
@@ -1024,13 +799,13 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1024 | if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len)) | 799 | if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len)) |
1025 | goto reset; | 800 | goto reset; |
1026 | if (opt_skb) { | 801 | if (opt_skb) { |
1027 | /* This is where we would goto ipv6_pktoptions. */ | 802 | /* XXX This is where we would goto ipv6_pktoptions. */ |
1028 | __kfree_skb(opt_skb); | 803 | __kfree_skb(opt_skb); |
1029 | } | 804 | } |
1030 | return 0; | 805 | return 0; |
1031 | 806 | ||
1032 | reset: | 807 | reset: |
1033 | dccp_v6_ctl_send_reset(skb); | 808 | dccp_v6_ctl_send_reset(sk, skb); |
1034 | discard: | 809 | discard: |
1035 | if (opt_skb != NULL) | 810 | if (opt_skb != NULL) |
1036 | __kfree_skb(opt_skb); | 811 | __kfree_skb(opt_skb); |
@@ -1043,12 +818,20 @@ static int dccp_v6_rcv(struct sk_buff **pskb) | |||
1043 | const struct dccp_hdr *dh; | 818 | const struct dccp_hdr *dh; |
1044 | struct sk_buff *skb = *pskb; | 819 | struct sk_buff *skb = *pskb; |
1045 | struct sock *sk; | 820 | struct sock *sk; |
821 | int min_cov; | ||
1046 | 822 | ||
1047 | /* Step 1: Check header basics: */ | 823 | /* Step 1: Check header basics */ |
1048 | 824 | ||
1049 | if (dccp_invalid_packet(skb)) | 825 | if (dccp_invalid_packet(skb)) |
1050 | goto discard_it; | 826 | goto discard_it; |
1051 | 827 | ||
828 | /* Step 1: If header checksum is incorrect, drop packet and return. */ | ||
829 | if (dccp_v6_csum_finish(skb, &skb->nh.ipv6h->saddr, | ||
830 | &skb->nh.ipv6h->daddr)) { | ||
831 | DCCP_WARN("dropped packet with invalid checksum\n"); | ||
832 | goto discard_it; | ||
833 | } | ||
834 | |||
1052 | dh = dccp_hdr(skb); | 835 | dh = dccp_hdr(skb); |
1053 | 836 | ||
1054 | DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); | 837 | DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); |
@@ -1068,11 +851,12 @@ static int dccp_v6_rcv(struct sk_buff **pskb) | |||
1068 | /* | 851 | /* |
1069 | * Step 2: | 852 | * Step 2: |
1070 | * If no socket ... | 853 | * If no socket ... |
1071 | * Generate Reset(No Connection) unless P.type == Reset | ||
1072 | * Drop packet and return | ||
1073 | */ | 854 | */ |
1074 | if (sk == NULL) | 855 | if (sk == NULL) { |
856 | dccp_pr_debug("failed to look up flow ID in table and " | ||
857 | "get corresponding socket\n"); | ||
1075 | goto no_dccp_socket; | 858 | goto no_dccp_socket; |
859 | } | ||
1076 | 860 | ||
1077 | /* | 861 | /* |
1078 | * Step 2: | 862 | * Step 2: |
@@ -1080,43 +864,226 @@ static int dccp_v6_rcv(struct sk_buff **pskb) | |||
1080 | * Generate Reset(No Connection) unless P.type == Reset | 864 | * Generate Reset(No Connection) unless P.type == Reset |
1081 | * Drop packet and return | 865 | * Drop packet and return |
1082 | */ | 866 | */ |
1083 | if (sk->sk_state == DCCP_TIME_WAIT) | 867 | if (sk->sk_state == DCCP_TIME_WAIT) { |
1084 | goto do_time_wait; | 868 | dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n"); |
869 | inet_twsk_put(inet_twsk(sk)); | ||
870 | goto no_dccp_socket; | ||
871 | } | ||
872 | |||
873 | /* | ||
874 | * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage | ||
875 | * o if MinCsCov = 0, only packets with CsCov = 0 are accepted | ||
876 | * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov | ||
877 | */ | ||
878 | min_cov = dccp_sk(sk)->dccps_pcrlen; | ||
879 | if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { | ||
880 | dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n", | ||
881 | dh->dccph_cscov, min_cov); | ||
882 | /* FIXME: send Data Dropped option (see also dccp_v4_rcv) */ | ||
883 | goto discard_and_relse; | ||
884 | } | ||
1085 | 885 | ||
1086 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 886 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
1087 | goto discard_and_relse; | 887 | goto discard_and_relse; |
1088 | 888 | ||
1089 | return sk_receive_skb(sk, skb) ? -1 : 0; | 889 | return sk_receive_skb(sk, skb, 1) ? -1 : 0; |
1090 | 890 | ||
1091 | no_dccp_socket: | 891 | no_dccp_socket: |
1092 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | 892 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |
1093 | goto discard_it; | 893 | goto discard_it; |
1094 | /* | 894 | /* |
1095 | * Step 2: | 895 | * Step 2: |
896 | * If no socket ... | ||
1096 | * Generate Reset(No Connection) unless P.type == Reset | 897 | * Generate Reset(No Connection) unless P.type == Reset |
1097 | * Drop packet and return | 898 | * Drop packet and return |
1098 | */ | 899 | */ |
1099 | if (dh->dccph_type != DCCP_PKT_RESET) { | 900 | if (dh->dccph_type != DCCP_PKT_RESET) { |
1100 | DCCP_SKB_CB(skb)->dccpd_reset_code = | 901 | DCCP_SKB_CB(skb)->dccpd_reset_code = |
1101 | DCCP_RESET_CODE_NO_CONNECTION; | 902 | DCCP_RESET_CODE_NO_CONNECTION; |
1102 | dccp_v6_ctl_send_reset(skb); | 903 | dccp_v6_ctl_send_reset(sk, skb); |
1103 | } | 904 | } |
1104 | discard_it: | ||
1105 | |||
1106 | /* | ||
1107 | * Discard frame | ||
1108 | */ | ||
1109 | 905 | ||
906 | discard_it: | ||
1110 | kfree_skb(skb); | 907 | kfree_skb(skb); |
1111 | return 0; | 908 | return 0; |
1112 | 909 | ||
1113 | discard_and_relse: | 910 | discard_and_relse: |
1114 | sock_put(sk); | 911 | sock_put(sk); |
1115 | goto discard_it; | 912 | goto discard_it; |
913 | } | ||
1116 | 914 | ||
1117 | do_time_wait: | 915 | static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, |
1118 | inet_twsk_put(inet_twsk(sk)); | 916 | int addr_len) |
1119 | goto no_dccp_socket; | 917 | { |
918 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr; | ||
919 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
920 | struct inet_sock *inet = inet_sk(sk); | ||
921 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
922 | struct dccp_sock *dp = dccp_sk(sk); | ||
923 | struct in6_addr *saddr = NULL, *final_p = NULL, final; | ||
924 | struct flowi fl; | ||
925 | struct dst_entry *dst; | ||
926 | int addr_type; | ||
927 | int err; | ||
928 | |||
929 | dp->dccps_role = DCCP_ROLE_CLIENT; | ||
930 | |||
931 | if (addr_len < SIN6_LEN_RFC2133) | ||
932 | return -EINVAL; | ||
933 | |||
934 | if (usin->sin6_family != AF_INET6) | ||
935 | return -EAFNOSUPPORT; | ||
936 | |||
937 | memset(&fl, 0, sizeof(fl)); | ||
938 | |||
939 | if (np->sndflow) { | ||
940 | fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK; | ||
941 | IP6_ECN_flow_init(fl.fl6_flowlabel); | ||
942 | if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) { | ||
943 | struct ip6_flowlabel *flowlabel; | ||
944 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | ||
945 | if (flowlabel == NULL) | ||
946 | return -EINVAL; | ||
947 | ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst); | ||
948 | fl6_sock_release(flowlabel); | ||
949 | } | ||
950 | } | ||
951 | /* | ||
952 | * connect() to INADDR_ANY means loopback (BSD'ism). | ||
953 | */ | ||
954 | if (ipv6_addr_any(&usin->sin6_addr)) | ||
955 | usin->sin6_addr.s6_addr[15] = 1; | ||
956 | |||
957 | addr_type = ipv6_addr_type(&usin->sin6_addr); | ||
958 | |||
959 | if (addr_type & IPV6_ADDR_MULTICAST) | ||
960 | return -ENETUNREACH; | ||
961 | |||
962 | if (addr_type & IPV6_ADDR_LINKLOCAL) { | ||
963 | if (addr_len >= sizeof(struct sockaddr_in6) && | ||
964 | usin->sin6_scope_id) { | ||
965 | /* If interface is set while binding, indices | ||
966 | * must coincide. | ||
967 | */ | ||
968 | if (sk->sk_bound_dev_if && | ||
969 | sk->sk_bound_dev_if != usin->sin6_scope_id) | ||
970 | return -EINVAL; | ||
971 | |||
972 | sk->sk_bound_dev_if = usin->sin6_scope_id; | ||
973 | } | ||
974 | |||
975 | /* Connect to link-local address requires an interface */ | ||
976 | if (!sk->sk_bound_dev_if) | ||
977 | return -EINVAL; | ||
978 | } | ||
979 | |||
980 | ipv6_addr_copy(&np->daddr, &usin->sin6_addr); | ||
981 | np->flow_label = fl.fl6_flowlabel; | ||
982 | |||
983 | /* | ||
984 | * DCCP over IPv4 | ||
985 | */ | ||
986 | if (addr_type == IPV6_ADDR_MAPPED) { | ||
987 | u32 exthdrlen = icsk->icsk_ext_hdr_len; | ||
988 | struct sockaddr_in sin; | ||
989 | |||
990 | SOCK_DEBUG(sk, "connect: ipv4 mapped\n"); | ||
991 | |||
992 | if (__ipv6_only_sock(sk)) | ||
993 | return -ENETUNREACH; | ||
994 | |||
995 | sin.sin_family = AF_INET; | ||
996 | sin.sin_port = usin->sin6_port; | ||
997 | sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; | ||
998 | |||
999 | icsk->icsk_af_ops = &dccp_ipv6_mapped; | ||
1000 | sk->sk_backlog_rcv = dccp_v4_do_rcv; | ||
1001 | |||
1002 | err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); | ||
1003 | if (err) { | ||
1004 | icsk->icsk_ext_hdr_len = exthdrlen; | ||
1005 | icsk->icsk_af_ops = &dccp_ipv6_af_ops; | ||
1006 | sk->sk_backlog_rcv = dccp_v6_do_rcv; | ||
1007 | goto failure; | ||
1008 | } else { | ||
1009 | ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF), | ||
1010 | inet->saddr); | ||
1011 | ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF), | ||
1012 | inet->rcv_saddr); | ||
1013 | } | ||
1014 | |||
1015 | return err; | ||
1016 | } | ||
1017 | |||
1018 | if (!ipv6_addr_any(&np->rcv_saddr)) | ||
1019 | saddr = &np->rcv_saddr; | ||
1020 | |||
1021 | fl.proto = IPPROTO_DCCP; | ||
1022 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | ||
1023 | ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr); | ||
1024 | fl.oif = sk->sk_bound_dev_if; | ||
1025 | fl.fl_ip_dport = usin->sin6_port; | ||
1026 | fl.fl_ip_sport = inet->sport; | ||
1027 | security_sk_classify_flow(sk, &fl); | ||
1028 | |||
1029 | if (np->opt != NULL && np->opt->srcrt != NULL) { | ||
1030 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | ||
1031 | |||
1032 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
1033 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
1034 | final_p = &final; | ||
1035 | } | ||
1036 | |||
1037 | err = ip6_dst_lookup(sk, &dst, &fl); | ||
1038 | if (err) | ||
1039 | goto failure; | ||
1040 | |||
1041 | if (final_p) | ||
1042 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
1043 | |||
1044 | err = xfrm_lookup(&dst, &fl, sk, 0); | ||
1045 | if (err < 0) | ||
1046 | goto failure; | ||
1047 | |||
1048 | if (saddr == NULL) { | ||
1049 | saddr = &fl.fl6_src; | ||
1050 | ipv6_addr_copy(&np->rcv_saddr, saddr); | ||
1051 | } | ||
1052 | |||
1053 | /* set the source address */ | ||
1054 | ipv6_addr_copy(&np->saddr, saddr); | ||
1055 | inet->rcv_saddr = LOOPBACK4_IPV6; | ||
1056 | |||
1057 | __ip6_dst_store(sk, dst, NULL, NULL); | ||
1058 | |||
1059 | icsk->icsk_ext_hdr_len = 0; | ||
1060 | if (np->opt != NULL) | ||
1061 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + | ||
1062 | np->opt->opt_nflen); | ||
1063 | |||
1064 | inet->dport = usin->sin6_port; | ||
1065 | |||
1066 | dccp_set_state(sk, DCCP_REQUESTING); | ||
1067 | err = inet6_hash_connect(&dccp_death_row, sk); | ||
1068 | if (err) | ||
1069 | goto late_failure; | ||
1070 | |||
1071 | dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32, | ||
1072 | np->daddr.s6_addr32, | ||
1073 | inet->sport, inet->dport); | ||
1074 | err = dccp_connect(sk); | ||
1075 | if (err) | ||
1076 | goto late_failure; | ||
1077 | |||
1078 | return 0; | ||
1079 | |||
1080 | late_failure: | ||
1081 | dccp_set_state(sk, DCCP_CLOSED); | ||
1082 | __sk_dst_reset(sk); | ||
1083 | failure: | ||
1084 | inet->dport = 0; | ||
1085 | sk->sk_route_caps = 0; | ||
1086 | return err; | ||
1120 | } | 1087 | } |
1121 | 1088 | ||
1122 | static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { | 1089 | static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { |
@@ -1179,6 +1146,10 @@ static int dccp_v6_destroy_sock(struct sock *sk) | |||
1179 | return inet6_destroy_sock(sk); | 1146 | return inet6_destroy_sock(sk); |
1180 | } | 1147 | } |
1181 | 1148 | ||
1149 | static struct timewait_sock_ops dccp6_timewait_sock_ops = { | ||
1150 | .twsk_obj_size = sizeof(struct dccp6_timewait_sock), | ||
1151 | }; | ||
1152 | |||
1182 | static struct proto dccp_v6_prot = { | 1153 | static struct proto dccp_v6_prot = { |
1183 | .name = "DCCPv6", | 1154 | .name = "DCCPv6", |
1184 | .owner = THIS_MODULE, | 1155 | .owner = THIS_MODULE, |