|
@@ -36,11 +36,6 @@
|
|
|
/* Socket used for sending RSTs and ACKs */
|
|
|
static struct socket *dccp_v6_ctl_socket;
|
|
|
|
|
|
-static void dccp_v6_ctl_send_reset(struct sk_buff *skb);
|
|
|
-static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb);
|
|
|
-
|
|
|
-static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
|
|
|
-
|
|
|
static struct inet_connection_sock_af_ops dccp_ipv6_mapped;
|
|
|
static struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
|
|
|
|
|
@@ -87,183 +82,6 @@ static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
|
|
|
dh->dccph_sport);
|
|
|
}
|
|
|
|
|
|
-static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
|
|
|
- int addr_len)
|
|
|
-{
|
|
|
- struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
|
|
|
- struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
- struct inet_sock *inet = inet_sk(sk);
|
|
|
- struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
- struct dccp_sock *dp = dccp_sk(sk);
|
|
|
- struct in6_addr *saddr = NULL, *final_p = NULL, final;
|
|
|
- struct flowi fl;
|
|
|
- struct dst_entry *dst;
|
|
|
- int addr_type;
|
|
|
- int err;
|
|
|
-
|
|
|
- dp->dccps_role = DCCP_ROLE_CLIENT;
|
|
|
-
|
|
|
- if (addr_len < SIN6_LEN_RFC2133)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (usin->sin6_family != AF_INET6)
|
|
|
- return -EAFNOSUPPORT;
|
|
|
-
|
|
|
- memset(&fl, 0, sizeof(fl));
|
|
|
-
|
|
|
- if (np->sndflow) {
|
|
|
- fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
|
|
|
- IP6_ECN_flow_init(fl.fl6_flowlabel);
|
|
|
- if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) {
|
|
|
- struct ip6_flowlabel *flowlabel;
|
|
|
- flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
|
|
|
- if (flowlabel == NULL)
|
|
|
- return -EINVAL;
|
|
|
- ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
|
|
|
- fl6_sock_release(flowlabel);
|
|
|
- }
|
|
|
- }
|
|
|
- /*
|
|
|
- * connect() to INADDR_ANY means loopback (BSD'ism).
|
|
|
- */
|
|
|
- if (ipv6_addr_any(&usin->sin6_addr))
|
|
|
- usin->sin6_addr.s6_addr[15] = 1;
|
|
|
-
|
|
|
- addr_type = ipv6_addr_type(&usin->sin6_addr);
|
|
|
-
|
|
|
- if (addr_type & IPV6_ADDR_MULTICAST)
|
|
|
- return -ENETUNREACH;
|
|
|
-
|
|
|
- if (addr_type & IPV6_ADDR_LINKLOCAL) {
|
|
|
- if (addr_len >= sizeof(struct sockaddr_in6) &&
|
|
|
- usin->sin6_scope_id) {
|
|
|
- /* If interface is set while binding, indices
|
|
|
- * must coincide.
|
|
|
- */
|
|
|
- if (sk->sk_bound_dev_if &&
|
|
|
- sk->sk_bound_dev_if != usin->sin6_scope_id)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- sk->sk_bound_dev_if = usin->sin6_scope_id;
|
|
|
- }
|
|
|
-
|
|
|
- /* Connect to link-local address requires an interface */
|
|
|
- if (!sk->sk_bound_dev_if)
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
|
|
|
- np->flow_label = fl.fl6_flowlabel;
|
|
|
-
|
|
|
- /*
|
|
|
- * DCCP over IPv4
|
|
|
- */
|
|
|
- if (addr_type == IPV6_ADDR_MAPPED) {
|
|
|
- u32 exthdrlen = icsk->icsk_ext_hdr_len;
|
|
|
- struct sockaddr_in sin;
|
|
|
-
|
|
|
- SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
|
|
|
-
|
|
|
- if (__ipv6_only_sock(sk))
|
|
|
- return -ENETUNREACH;
|
|
|
-
|
|
|
- sin.sin_family = AF_INET;
|
|
|
- sin.sin_port = usin->sin6_port;
|
|
|
- sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
|
|
|
-
|
|
|
- icsk->icsk_af_ops = &dccp_ipv6_mapped;
|
|
|
- sk->sk_backlog_rcv = dccp_v4_do_rcv;
|
|
|
-
|
|
|
- err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
|
|
|
- if (err) {
|
|
|
- icsk->icsk_ext_hdr_len = exthdrlen;
|
|
|
- icsk->icsk_af_ops = &dccp_ipv6_af_ops;
|
|
|
- sk->sk_backlog_rcv = dccp_v6_do_rcv;
|
|
|
- goto failure;
|
|
|
- } else {
|
|
|
- ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
|
|
|
- inet->saddr);
|
|
|
- ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
|
|
|
- inet->rcv_saddr);
|
|
|
- }
|
|
|
-
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- if (!ipv6_addr_any(&np->rcv_saddr))
|
|
|
- saddr = &np->rcv_saddr;
|
|
|
-
|
|
|
- fl.proto = IPPROTO_DCCP;
|
|
|
- ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
|
|
|
- ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr);
|
|
|
- fl.oif = sk->sk_bound_dev_if;
|
|
|
- fl.fl_ip_dport = usin->sin6_port;
|
|
|
- fl.fl_ip_sport = inet->sport;
|
|
|
- security_sk_classify_flow(sk, &fl);
|
|
|
-
|
|
|
- if (np->opt != NULL && np->opt->srcrt != NULL) {
|
|
|
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
|
|
|
-
|
|
|
- ipv6_addr_copy(&final, &fl.fl6_dst);
|
|
|
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
|
|
|
- final_p = &final;
|
|
|
- }
|
|
|
-
|
|
|
- err = ip6_dst_lookup(sk, &dst, &fl);
|
|
|
- if (err)
|
|
|
- goto failure;
|
|
|
-
|
|
|
- if (final_p)
|
|
|
- ipv6_addr_copy(&fl.fl6_dst, final_p);
|
|
|
-
|
|
|
- err = xfrm_lookup(&dst, &fl, sk, 0);
|
|
|
- if (err < 0)
|
|
|
- goto failure;
|
|
|
-
|
|
|
- if (saddr == NULL) {
|
|
|
- saddr = &fl.fl6_src;
|
|
|
- ipv6_addr_copy(&np->rcv_saddr, saddr);
|
|
|
- }
|
|
|
-
|
|
|
- /* set the source address */
|
|
|
- ipv6_addr_copy(&np->saddr, saddr);
|
|
|
- inet->rcv_saddr = LOOPBACK4_IPV6;
|
|
|
-
|
|
|
- __ip6_dst_store(sk, dst, NULL, NULL);
|
|
|
-
|
|
|
- icsk->icsk_ext_hdr_len = 0;
|
|
|
- if (np->opt != NULL)
|
|
|
- icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
|
|
|
- np->opt->opt_nflen);
|
|
|
-
|
|
|
- inet->dport = usin->sin6_port;
|
|
|
-
|
|
|
- dccp_set_state(sk, DCCP_REQUESTING);
|
|
|
- err = inet6_hash_connect(&dccp_death_row, sk);
|
|
|
- if (err)
|
|
|
- goto late_failure;
|
|
|
- /* FIXME */
|
|
|
-#if 0
|
|
|
- dp->dccps_gar = secure_dccp_v6_sequence_number(np->saddr.s6_addr32,
|
|
|
- np->daddr.s6_addr32,
|
|
|
- inet->sport,
|
|
|
- inet->dport);
|
|
|
-#endif
|
|
|
- err = dccp_connect(sk);
|
|
|
- if (err)
|
|
|
- goto late_failure;
|
|
|
-
|
|
|
- return 0;
|
|
|
-
|
|
|
-late_failure:
|
|
|
- dccp_set_state(sk, DCCP_CLOSED);
|
|
|
- __sk_dst_reset(sk);
|
|
|
-failure:
|
|
|
- inet->dport = 0;
|
|
|
- sk->sk_route_caps = 0;
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
|
|
int type, int code, int offset, __be32 info)
|
|
|
{
|
|
@@ -487,19 +305,6 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req)
|
|
|
kfree_skb(inet6_rsk(req)->pktopts);
|
|
|
}
|
|
|
|
|
|
-static struct request_sock_ops dccp6_request_sock_ops = {
|
|
|
- .family = AF_INET6,
|
|
|
- .obj_size = sizeof(struct dccp6_request_sock),
|
|
|
- .rtx_syn_ack = dccp_v6_send_response,
|
|
|
- .send_ack = dccp_reqsk_send_ack,
|
|
|
- .destructor = dccp_v6_reqsk_destructor,
|
|
|
- .send_reset = dccp_v6_ctl_send_reset,
|
|
|
-};
|
|
|
-
|
|
|
-static struct timewait_sock_ops dccp6_timewait_sock_ops = {
|
|
|
- .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
|
|
|
-};
|
|
|
-
|
|
|
static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
|
|
|
{
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
@@ -580,6 +385,15 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
|
|
|
kfree_skb(skb);
|
|
|
}
|
|
|
|
|
|
+static struct request_sock_ops dccp6_request_sock_ops = {
|
|
|
+ .family = AF_INET6,
|
|
|
+ .obj_size = sizeof(struct dccp6_request_sock),
|
|
|
+ .rtx_syn_ack = dccp_v6_send_response,
|
|
|
+ .send_ack = dccp_reqsk_send_ack,
|
|
|
+ .destructor = dccp_v6_reqsk_destructor,
|
|
|
+ .send_reset = dccp_v6_ctl_send_reset,
|
|
|
+};
|
|
|
+
|
|
|
static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
|
|
|
{
|
|
|
const struct dccp_hdr *dh = dccp_hdr(skb);
|
|
@@ -1062,6 +876,183 @@ discard_and_relse:
|
|
|
goto discard_it;
|
|
|
}
|
|
|
|
|
|
+static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
|
|
|
+ int addr_len)
|
|
|
+{
|
|
|
+ struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
|
|
|
+ struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
+ struct inet_sock *inet = inet_sk(sk);
|
|
|
+ struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
+ struct dccp_sock *dp = dccp_sk(sk);
|
|
|
+ struct in6_addr *saddr = NULL, *final_p = NULL, final;
|
|
|
+ struct flowi fl;
|
|
|
+ struct dst_entry *dst;
|
|
|
+ int addr_type;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ dp->dccps_role = DCCP_ROLE_CLIENT;
|
|
|
+
|
|
|
+ if (addr_len < SIN6_LEN_RFC2133)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (usin->sin6_family != AF_INET6)
|
|
|
+ return -EAFNOSUPPORT;
|
|
|
+
|
|
|
+ memset(&fl, 0, sizeof(fl));
|
|
|
+
|
|
|
+ if (np->sndflow) {
|
|
|
+ fl.fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
|
|
|
+ IP6_ECN_flow_init(fl.fl6_flowlabel);
|
|
|
+ if (fl.fl6_flowlabel & IPV6_FLOWLABEL_MASK) {
|
|
|
+ struct ip6_flowlabel *flowlabel;
|
|
|
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
|
|
|
+ if (flowlabel == NULL)
|
|
|
+ return -EINVAL;
|
|
|
+ ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
|
|
|
+ fl6_sock_release(flowlabel);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * connect() to INADDR_ANY means loopback (BSD'ism).
|
|
|
+ */
|
|
|
+ if (ipv6_addr_any(&usin->sin6_addr))
|
|
|
+ usin->sin6_addr.s6_addr[15] = 1;
|
|
|
+
|
|
|
+ addr_type = ipv6_addr_type(&usin->sin6_addr);
|
|
|
+
|
|
|
+ if (addr_type & IPV6_ADDR_MULTICAST)
|
|
|
+ return -ENETUNREACH;
|
|
|
+
|
|
|
+ if (addr_type & IPV6_ADDR_LINKLOCAL) {
|
|
|
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
|
|
|
+ usin->sin6_scope_id) {
|
|
|
+ /* If interface is set while binding, indices
|
|
|
+ * must coincide.
|
|
|
+ */
|
|
|
+ if (sk->sk_bound_dev_if &&
|
|
|
+ sk->sk_bound_dev_if != usin->sin6_scope_id)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ sk->sk_bound_dev_if = usin->sin6_scope_id;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Connect to link-local address requires an interface */
|
|
|
+ if (!sk->sk_bound_dev_if)
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
|
|
|
+ np->flow_label = fl.fl6_flowlabel;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * DCCP over IPv4
|
|
|
+ */
|
|
|
+ if (addr_type == IPV6_ADDR_MAPPED) {
|
|
|
+ u32 exthdrlen = icsk->icsk_ext_hdr_len;
|
|
|
+ struct sockaddr_in sin;
|
|
|
+
|
|
|
+ SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
|
|
|
+
|
|
|
+ if (__ipv6_only_sock(sk))
|
|
|
+ return -ENETUNREACH;
|
|
|
+
|
|
|
+ sin.sin_family = AF_INET;
|
|
|
+ sin.sin_port = usin->sin6_port;
|
|
|
+ sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
|
|
|
+
|
|
|
+ icsk->icsk_af_ops = &dccp_ipv6_mapped;
|
|
|
+ sk->sk_backlog_rcv = dccp_v4_do_rcv;
|
|
|
+
|
|
|
+ err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
|
|
|
+ if (err) {
|
|
|
+ icsk->icsk_ext_hdr_len = exthdrlen;
|
|
|
+ icsk->icsk_af_ops = &dccp_ipv6_af_ops;
|
|
|
+ sk->sk_backlog_rcv = dccp_v6_do_rcv;
|
|
|
+ goto failure;
|
|
|
+ } else {
|
|
|
+ ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
|
|
|
+ inet->saddr);
|
|
|
+ ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
|
|
|
+ inet->rcv_saddr);
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ipv6_addr_any(&np->rcv_saddr))
|
|
|
+ saddr = &np->rcv_saddr;
|
|
|
+
|
|
|
+ fl.proto = IPPROTO_DCCP;
|
|
|
+ ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
|
|
|
+ ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr);
|
|
|
+ fl.oif = sk->sk_bound_dev_if;
|
|
|
+ fl.fl_ip_dport = usin->sin6_port;
|
|
|
+ fl.fl_ip_sport = inet->sport;
|
|
|
+ security_sk_classify_flow(sk, &fl);
|
|
|
+
|
|
|
+ if (np->opt != NULL && np->opt->srcrt != NULL) {
|
|
|
+ const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
|
|
|
+
|
|
|
+ ipv6_addr_copy(&final, &fl.fl6_dst);
|
|
|
+ ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
|
|
|
+ final_p = &final;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = ip6_dst_lookup(sk, &dst, &fl);
|
|
|
+ if (err)
|
|
|
+ goto failure;
|
|
|
+
|
|
|
+ if (final_p)
|
|
|
+ ipv6_addr_copy(&fl.fl6_dst, final_p);
|
|
|
+
|
|
|
+ err = xfrm_lookup(&dst, &fl, sk, 0);
|
|
|
+ if (err < 0)
|
|
|
+ goto failure;
|
|
|
+
|
|
|
+ if (saddr == NULL) {
|
|
|
+ saddr = &fl.fl6_src;
|
|
|
+ ipv6_addr_copy(&np->rcv_saddr, saddr);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* set the source address */
|
|
|
+ ipv6_addr_copy(&np->saddr, saddr);
|
|
|
+ inet->rcv_saddr = LOOPBACK4_IPV6;
|
|
|
+
|
|
|
+ __ip6_dst_store(sk, dst, NULL, NULL);
|
|
|
+
|
|
|
+ icsk->icsk_ext_hdr_len = 0;
|
|
|
+ if (np->opt != NULL)
|
|
|
+ icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
|
|
|
+ np->opt->opt_nflen);
|
|
|
+
|
|
|
+ inet->dport = usin->sin6_port;
|
|
|
+
|
|
|
+ dccp_set_state(sk, DCCP_REQUESTING);
|
|
|
+ err = inet6_hash_connect(&dccp_death_row, sk);
|
|
|
+ if (err)
|
|
|
+ goto late_failure;
|
|
|
+ /* FIXME */
|
|
|
+#if 0
|
|
|
+ dp->dccps_gar = secure_dccp_v6_sequence_number(np->saddr.s6_addr32,
|
|
|
+ np->daddr.s6_addr32,
|
|
|
+ inet->sport,
|
|
|
+ inet->dport);
|
|
|
+#endif
|
|
|
+ err = dccp_connect(sk);
|
|
|
+ if (err)
|
|
|
+ goto late_failure;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+late_failure:
|
|
|
+ dccp_set_state(sk, DCCP_CLOSED);
|
|
|
+ __sk_dst_reset(sk);
|
|
|
+failure:
|
|
|
+ inet->dport = 0;
|
|
|
+ sk->sk_route_caps = 0;
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
|
|
|
.queue_xmit = inet6_csk_xmit,
|
|
|
.send_check = dccp_v6_send_check,
|
|
@@ -1122,6 +1113,10 @@ static int dccp_v6_destroy_sock(struct sock *sk)
|
|
|
return inet6_destroy_sock(sk);
|
|
|
}
|
|
|
|
|
|
+static struct timewait_sock_ops dccp6_timewait_sock_ops = {
|
|
|
+ .twsk_obj_size = sizeof(struct dccp6_timewait_sock),
|
|
|
+};
|
|
|
+
|
|
|
static struct proto dccp_v6_prot = {
|
|
|
.name = "DCCPv6",
|
|
|
.owner = THIS_MODULE,
|