net: spread __net_init, __net_exit
[safe/jmp/linux-2.6] / net / dccp / ipv6.c
index da50912..1aec634 100644 (file)
@@ -35,8 +35,8 @@
 
 /* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */
 
-static struct inet_connection_sock_af_ops dccp_ipv6_mapped;
-static struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
+static const struct inet_connection_sock_af_ops dccp_ipv6_mapped;
+static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
 
 static void dccp_v6_hash(struct sock *sk)
 {
@@ -46,7 +46,7 @@ static void dccp_v6_hash(struct sock *sk)
                        return;
                }
                local_bh_disable();
-               __inet6_hash(sk);
+               __inet6_hash(sk, NULL);
                local_bh_enable();
        }
 }
@@ -85,22 +85,31 @@ static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb)
 }
 
 static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                       int type, int code, int offset, __be32 info)
+                       u8 type, u8 code, int offset, __be32 info)
 {
        struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data;
        const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
+       struct dccp_sock *dp;
        struct ipv6_pinfo *np;
        struct sock *sk;
        int err;
        __u64 seq;
        struct net *net = dev_net(skb->dev);
 
+       if (skb->len < offset + sizeof(*dh) ||
+           skb->len < offset + __dccp_basic_hdr_len(dh)) {
+               ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
+                                  ICMP6_MIB_INERRORS);
+               return;
+       }
+
        sk = inet6_lookup(net, &dccp_hashinfo,
                        &hdr->daddr, dh->dccph_dport,
                        &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
 
        if (sk == NULL) {
-               ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
+               ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
+                                  ICMP6_MIB_INERRORS);
                return;
        }
 
@@ -116,6 +125,14 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        if (sk->sk_state == DCCP_CLOSED)
                goto out;
 
+       dp = dccp_sk(sk);
+       seq = dccp_hdr_seq(dh);
+       if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
+           !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
+               NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
+               goto out;
+       }
+
        np = inet6_sk(sk);
 
        if (type == ICMPV6_PKT_TOOBIG) {
@@ -141,8 +158,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                        ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
                        ipv6_addr_copy(&fl.fl6_src, &np->saddr);
                        fl.oif = sk->sk_bound_dev_if;
-                       fl.fl_ip_dport = inet->dport;
-                       fl.fl_ip_sport = inet->sport;
+                       fl.fl_ip_dport = inet->inet_dport;
+                       fl.fl_ip_sport = inet->inet_sport;
                        security_sk_classify_flow(sk, &fl);
 
                        err = ip6_dst_lookup(sk, &dst, &fl);
@@ -151,7 +168,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                                goto out;
                        }
 
-                       err = xfrm_lookup(&dst, &fl, sk, 0);
+                       err = xfrm_lookup(net, &dst, &fl, sk, 0);
                        if (err < 0) {
                                sk->sk_err_soft = -err;
                                goto out;
@@ -168,7 +185,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
        icmpv6_err_convert(type, code, &err);
 
-       seq = dccp_hdr_seq(dh);
        /* Might be for an request_sock */
        switch (sk->sk_state) {
                struct request_sock *req, **prev;
@@ -225,7 +241,8 @@ out:
 }
 
 
-static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
+static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
+                                struct request_values *rv_unused)
 {
        struct inet6_request_sock *ireq6 = inet6_rsk(req);
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -243,7 +260,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
        fl.fl6_flowlabel = 0;
        fl.oif = ireq6->iif;
        fl.fl_ip_dport = inet_rsk(req)->rmt_port;
-       fl.fl_ip_sport = inet_sk(sk)->sport;
+       fl.fl_ip_sport = inet_rsk(req)->loc_port;
        security_req_classify_flow(req, &fl);
 
        opt = np->opt;
@@ -263,7 +280,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
        if (final_p)
                ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-       err = xfrm_lookup(&dst, &fl, sk, 0);
+       err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0);
        if (err < 0)
                goto done;
 
@@ -288,6 +305,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+       dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
        if (inet6_rsk(req)->pktopts != NULL)
                kfree_skb(inet6_rsk(req)->pktopts);
 }
@@ -297,8 +315,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
        struct ipv6hdr *rxip6h;
        struct sk_buff *skb;
        struct flowi fl;
-       struct net *net = dev_net(rxskb->dst->dev);
+       struct net *net = dev_net(skb_dst(rxskb)->dev);
        struct sock *ctl_sk = net->dccp.v6_ctl_sk;
+       struct dst_entry *dst;
 
        if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
                return;
@@ -325,8 +344,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
        security_skb_classify_flow(rxskb, &fl);
 
        /* sk = NULL, but it is safe for now. RST socket required. */
-       if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) {
-               if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
+       if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
+               if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
+                       skb_dst_set(skb, dst);
                        ip6_xmit(ctl_sk, skb, &fl, NULL, 0);
                        DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
                        DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
@@ -410,7 +430,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        if (req == NULL)
                goto drop;
 
-       dccp_reqsk_init(req, skb);
+       if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+               goto drop_and_free;
 
        dreq = dccp_rsk(req);
        if (dccp_parse_options(sk, dreq, skb))
@@ -448,7 +469,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        dreq->dreq_iss     = dccp_v6_init_sequence(skb);
        dreq->dreq_service = service;
 
-       if (dccp_v6_send_response(sk, req))
+       if (dccp_v6_send_response(sk, req, NULL))
                goto drop_and_free;
 
        inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
@@ -490,11 +511,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 
                memcpy(newnp, np, sizeof(struct ipv6_pinfo));
 
-               ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
-                             newinet->daddr);
+               ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
 
-               ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
-                             newinet->saddr);
+               ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
 
                ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
 
@@ -542,7 +561,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
                ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
                fl.oif = sk->sk_bound_dev_if;
                fl.fl_ip_dport = inet_rsk(req)->rmt_port;
-               fl.fl_ip_sport = inet_sk(sk)->sport;
+               fl.fl_ip_sport = inet_rsk(req)->loc_port;
                security_sk_classify_flow(sk, &fl);
 
                if (ip6_dst_lookup(sk, &dst, &fl))
@@ -551,7 +570,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
                if (final_p)
                        ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-               if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+               if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
                        goto out;
        }
 
@@ -622,9 +641,10 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 
        dccp_sync_mss(newsk, dst_mtu(dst));
 
-       newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
+       newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
+       newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
-       __inet6_hash(newsk);
+       __inet6_hash(newsk, NULL);
        __inet_inherit_port(sk, newsk);
 
        return newsk;
@@ -791,10 +811,8 @@ static int dccp_v6_rcv(struct sk_buff *skb)
 
        /* Step 2:
         *      Look up flow ID in table and get corresponding socket */
-       sk = __inet6_lookup(dev_net(skb->dst->dev), &dccp_hashinfo,
-                           &ipv6_hdr(skb)->saddr, dh->dccph_sport,
-                           &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),
-                           inet6_iif(skb));
+       sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
+                               dh->dccph_sport, dh->dccph_dport);
        /*
         * Step 2:
         *      If no socket ...
@@ -952,12 +970,9 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                        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);
                }
+               ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
+               ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, &np->rcv_saddr);
 
                return err;
        }
@@ -970,7 +985,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        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;
+       fl.fl_ip_sport = inet->inet_sport;
        security_sk_classify_flow(sk, &fl);
 
        if (np->opt != NULL && np->opt->srcrt != NULL) {
@@ -988,7 +1003,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        if (final_p)
                ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-       err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT);
+       err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
        if (err < 0) {
                if (err == -EREMOTE)
                        err = ip6_dst_blackhole(sk, &dst, &fl);
@@ -1003,7 +1018,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        /* set the source address */
        ipv6_addr_copy(&np->saddr, saddr);
-       inet->rcv_saddr = LOOPBACK4_IPV6;
+       inet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
        __ip6_dst_store(sk, dst, NULL, NULL);
 
@@ -1012,7 +1027,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
                                          np->opt->opt_nflen);
 
-       inet->dport = usin->sin6_port;
+       inet->inet_dport = usin->sin6_port;
 
        dccp_set_state(sk, DCCP_REQUESTING);
        err = inet6_hash_connect(&dccp_death_row, sk);
@@ -1021,7 +1036,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
                                                      np->daddr.s6_addr32,
-                                                     inet->sport, inet->dport);
+                                                     inet->inet_sport,
+                                                     inet->inet_dport);
        err = dccp_connect(sk);
        if (err)
                goto late_failure;
@@ -1032,12 +1048,12 @@ late_failure:
        dccp_set_state(sk, DCCP_CLOSED);
        __sk_dst_reset(sk);
 failure:
-       inet->dport = 0;
+       inet->inet_dport = 0;
        sk->sk_route_caps = 0;
        return err;
 }
 
-static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
+static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
        .queue_xmit        = inet6_csk_xmit,
        .send_check        = dccp_v6_send_check,
        .rebuild_header    = inet6_sk_rebuild_header,
@@ -1058,7 +1074,7 @@ static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
 /*
  *     DCCP over IPv4 via INET6 API
  */
-static struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
+static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
        .queue_xmit        = ip_queue_xmit,
        .send_check        = dccp_v4_send_check,
        .rebuild_header    = inet_sk_rebuild_header,
@@ -1124,6 +1140,7 @@ static struct proto dccp_v6_prot = {
        .orphan_count      = &dccp_orphan_count,
        .max_header        = MAX_DCCP_HEADER,
        .obj_size          = sizeof(struct dccp6_sock),
+       .slab_flags        = SLAB_DESTROY_BY_RCU,
        .rsk_prot          = &dccp6_request_sock_ops,
        .twsk_prot         = &dccp6_timewait_sock_ops,
        .h.hashinfo        = &dccp_hashinfo,
@@ -1133,13 +1150,13 @@ static struct proto dccp_v6_prot = {
 #endif
 };
 
-static struct inet6_protocol dccp_v6_protocol = {
+static const struct inet6_protocol dccp_v6_protocol = {
        .handler        = dccp_v6_rcv,
        .err_handler    = dccp_v6_err,
        .flags          = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
 };
 
-static struct proto_ops inet6_dccp_ops = {
+static const struct proto_ops inet6_dccp_ops = {
        .family            = PF_INET6,
        .owner             = THIS_MODULE,
        .release           = inet6_release,
@@ -1169,11 +1186,10 @@ static struct inet_protosw dccp_v6_protosw = {
        .protocol       = IPPROTO_DCCP,
        .prot           = &dccp_v6_prot,
        .ops            = &inet6_dccp_ops,
-       .capability     = -1,
        .flags          = INET_PROTOSW_ICSK,
 };
 
-static int dccp_v6_init_net(struct net *net)
+static int __net_init dccp_v6_init_net(struct net *net)
 {
        int err;
 
@@ -1182,7 +1198,7 @@ static int dccp_v6_init_net(struct net *net)
        return err;
 }
 
-static void dccp_v6_exit_net(struct net *net)
+static void __net_exit dccp_v6_exit_net(struct net *net)
 {
        inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
 }