]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/dccp/ipv4.c
[PATCH] lpfc 8.1.3: Change version number to 8.1.3
[linux-2.6-omap-h63xx.git] / net / dccp / ipv4.c
index 0ce7d0fe5ee7e5ab041d94019c683418570f2b3d..dc0487b5bacec375dda26bbdc4515b5a5cedc621 100644 (file)
@@ -19,7 +19,9 @@
 
 #include <net/icmp.h>
 #include <net/inet_hashtables.h>
+#include <net/inet_sock.h>
 #include <net/sock.h>
+#include <net/timewait_sock.h>
 #include <net/tcp_states.h>
 #include <net/xfrm.h>
 
@@ -46,171 +48,14 @@ static void dccp_v4_hash(struct sock *sk)
        inet_hash(&dccp_hashinfo, sk);
 }
 
-static void dccp_v4_unhash(struct sock *sk)
+void dccp_unhash(struct sock *sk)
 {
        inet_unhash(&dccp_hashinfo, sk);
 }
 
-/* called with local bh disabled */
-static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
-                                     struct inet_timewait_sock **twp)
-{
-       struct inet_sock *inet = inet_sk(sk);
-       const u32 daddr = inet->rcv_saddr;
-       const u32 saddr = inet->daddr;
-       const int dif = sk->sk_bound_dev_if;
-       INET_ADDR_COOKIE(acookie, saddr, daddr)
-       const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
-       unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
-       struct inet_ehash_bucket *head = inet_ehash_bucket(&dccp_hashinfo, hash);
-       const struct sock *sk2;
-       const struct hlist_node *node;
-       struct inet_timewait_sock *tw;
-
-       prefetch(head->chain.first);
-       write_lock(&head->lock);
-
-       /* Check TIME-WAIT sockets first. */
-       sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) {
-               tw = inet_twsk(sk2);
-
-               if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
-                       goto not_unique;
-       }
-       tw = NULL;
-
-       /* And established part... */
-       sk_for_each(sk2, node, &head->chain) {
-               if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
-                       goto not_unique;
-       }
-
-       /* Must record num and sport now. Otherwise we will see
-        * in hash table socket with a funny identity. */
-       inet->num = lport;
-       inet->sport = htons(lport);
-       sk->sk_hash = hash;
-       BUG_TRAP(sk_unhashed(sk));
-       __sk_add_node(sk, &head->chain);
-       sock_prot_inc_use(sk->sk_prot);
-       write_unlock(&head->lock);
-
-       if (twp != NULL) {
-               *twp = tw;
-               NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
-       } else if (tw != NULL) {
-               /* Silly. Should hash-dance instead... */
-               inet_twsk_deschedule(tw, &dccp_death_row);
-               NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
-
-               inet_twsk_put(tw);
-       }
-
-       return 0;
+EXPORT_SYMBOL_GPL(dccp_unhash);
 
-not_unique:
-       write_unlock(&head->lock);
-       return -EADDRNOTAVAIL;
-}
-
-/*
- * Bind a port for a connect operation and hash it.
- */
-static int dccp_v4_hash_connect(struct sock *sk)
-{
-       const unsigned short snum = inet_sk(sk)->num;
-       struct inet_bind_hashbucket *head;
-       struct inet_bind_bucket *tb;
-       int ret;
-
-       if (snum == 0) {
-               int low = sysctl_local_port_range[0];
-               int high = sysctl_local_port_range[1];
-               int remaining = (high - low) + 1;
-               int rover = net_random() % (high - low) + low;
-               struct hlist_node *node;
-               struct inet_timewait_sock *tw = NULL;
-
-               local_bh_disable();
-               do {
-                       head = &dccp_hashinfo.bhash[inet_bhashfn(rover,
-                                                   dccp_hashinfo.bhash_size)];
-                       spin_lock(&head->lock);
-
-                       /* Does not bother with rcv_saddr checks,
-                        * because the established check is already
-                        * unique enough.
-                        */
-                       inet_bind_bucket_for_each(tb, node, &head->chain) {
-                               if (tb->port == rover) {
-                                       BUG_TRAP(!hlist_empty(&tb->owners));
-                                       if (tb->fastreuse >= 0)
-                                               goto next_port;
-                                       if (!__dccp_v4_check_established(sk,
-                                                                        rover,
-                                                                        &tw))
-                                               goto ok;
-                                       goto next_port;
-                               }
-                       }
-
-                       tb = inet_bind_bucket_create(dccp_hashinfo.bind_bucket_cachep,
-                                                    head, rover);
-                       if (tb == NULL) {
-                               spin_unlock(&head->lock);
-                               break;
-                       }
-                       tb->fastreuse = -1;
-                       goto ok;
-
-               next_port:
-                       spin_unlock(&head->lock);
-                       if (++rover > high)
-                               rover = low;
-               } while (--remaining > 0);
-
-               local_bh_enable();
-
-               return -EADDRNOTAVAIL;
-
-ok:
-               /* All locks still held and bhs disabled */
-               inet_bind_hash(sk, tb, rover);
-               if (sk_unhashed(sk)) {
-                       inet_sk(sk)->sport = htons(rover);
-                       __inet_hash(&dccp_hashinfo, sk, 0);
-               }
-               spin_unlock(&head->lock);
-
-               if (tw != NULL) {
-                       inet_twsk_deschedule(tw, &dccp_death_row);
-                       inet_twsk_put(tw);
-               }
-
-               ret = 0;
-               goto out;
-       }
-
-       head = &dccp_hashinfo.bhash[inet_bhashfn(snum,
-                                                dccp_hashinfo.bhash_size)];
-       tb   = inet_csk(sk)->icsk_bind_hash;
-       spin_lock_bh(&head->lock);
-       if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
-               __inet_hash(&dccp_hashinfo, sk, 0);
-               spin_unlock_bh(&head->lock);
-               return 0;
-       } else {
-               spin_unlock(&head->lock);
-               /* No definite answer... Walk to established hash table */
-               ret = __dccp_v4_check_established(sk, snum, NULL);
-out:
-               local_bh_enable();
-               return ret;
-       }
-}
-
-static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
-                          int addr_len)
+int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct inet_sock *inet = inet_sk(sk);
        struct dccp_sock *dp = dccp_sk(sk);
@@ -260,9 +105,9 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
        inet->dport = usin->sin_port;
        inet->daddr = daddr;
 
-       dp->dccps_ext_header_len = 0;
+       inet_csk(sk)->icsk_ext_hdr_len = 0;
        if (inet->opt != NULL)
-               dp->dccps_ext_header_len = inet->opt->optlen;
+               inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
        /*
         * Socket identity is still unknown (sport may be zero).
         * However we set state to DCCP_REQUESTING and not releasing socket
@@ -270,11 +115,12 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
         * complete initialization after this.
         */
        dccp_set_state(sk, DCCP_REQUESTING);
-       err = dccp_v4_hash_connect(sk);
+       err = inet_hash_connect(&dccp_death_row, sk);
        if (err != 0)
                goto failure;
 
-       err = ip_route_newports(&rt, inet->sport, inet->dport, sk);
+       err = ip_route_newports(&rt, IPPROTO_DCCP, inet->sport, inet->dport,
+                               sk);
        if (err != 0)
                goto failure;
 
@@ -288,16 +134,6 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
                                                            usin->sin_port);
        dccp_update_gss(sk, dp->dccps_iss);
 
-       /*
-        * SWL and AWL are initially adjusted so that they are not less than
-        * the initial Sequence Numbers received and sent, respectively:
-        *      SWL := max(GSR + 1 - floor(W/4), ISR),
-        *      AWL := max(GSS - W' + 1, ISS).
-        * These adjustments MUST be applied only at the beginning of the
-        * connection.
-        */
-       dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
-
        inet->id = dp->dccps_iss ^ jiffies;
 
        err = dccp_connect(sk);
@@ -317,6 +153,8 @@ failure:
        goto out;
 }
 
+EXPORT_SYMBOL_GPL(dccp_v4_connect);
+
 /*
  * This routine does path mtu discovery as defined in RFC1191.
  */
@@ -355,7 +193,7 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk,
        mtu = dst_mtu(dst);
 
        if (inet->pmtudisc != IP_PMTUDISC_DONT &&
-           dp->dccps_pmtu_cookie > mtu) {
+           inet_csk(sk)->icsk_pmtu_cookie > mtu) {
                dccp_sync_mss(sk, mtu);
 
                /*
@@ -608,7 +446,7 @@ out:
 }
 
 /* This routine computes an IPv4 DCCP checksum. */
-static void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
+void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
 {
        const struct inet_sock *inet = inet_sk(sk);
        struct dccp_hdr *dh = dccp_hdr(skb);
@@ -616,6 +454,8 @@ static void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
        dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr, inet->daddr);
 }
 
+EXPORT_SYMBOL_GPL(dccp_v4_send_check);
+
 int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code)
 {
        struct sk_buff *skb;
@@ -651,16 +491,6 @@ static inline u64 dccp_v4_init_sequence(const struct sock *sk,
                                           dccp_hdr(skb)->dccph_sport);
 }
 
-static inline int dccp_bad_service_code(const struct sock *sk,
-                                       const __u32 service)
-{
-       const struct dccp_sock *dp = dccp_sk(sk);
-
-       if (dp->dccps_service == service)
-               return 0;
-       return !dccp_list_has_service(dp->dccps_service_list, service);
-}
-
 int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 {
        struct inet_request_sock *ireq;
@@ -672,7 +502,6 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        const __u32 service = dccp_hdr_request(skb)->dccph_req_service;
        struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
        __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
-       struct dst_entry *dst = NULL;
 
        /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */
        if (((struct rtable *)skb->dst)->rt_flags &
@@ -713,7 +542,6 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        ireq = inet_rsk(req);
        ireq->loc_addr = daddr;
        ireq->rmt_addr = saddr;
-       /* FIXME: Merge Aristeu's option parsing code when ready */
        req->rcv_wnd    = 100; /* Fake, option parsing will get the
                                  right value */
        ireq->opt       = NULL;
@@ -731,23 +559,22 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        dreq->dreq_iss     = dccp_v4_init_sequence(sk, skb);
        dreq->dreq_service = service;
 
-       if (dccp_v4_send_response(sk, req, dst))
+       if (dccp_v4_send_response(sk, req, NULL))
                goto drop_and_free;
 
        inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
        return 0;
 
 drop_and_free:
-       /*
-        * FIXME: should be reqsk_free after implementing req->rsk_ops
-        */
-       __reqsk_free(req);
+       reqsk_free(req);
 drop:
        DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
        dcb->dccpd_reset_code = reset_code;
        return -1;
 }
 
+EXPORT_SYMBOL_GPL(dccp_v4_conn_request);
+
 /*
  * The three way handshake has completed - we got a valid ACK or DATAACK -
  * now create the new socket.
@@ -802,6 +629,8 @@ exit:
        return NULL;
 }
 
+EXPORT_SYMBOL_GPL(dccp_v4_request_recv_sock);
+
 static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
 {
        const struct dccp_hdr *dh = dccp_hdr(skb);
@@ -1021,7 +850,9 @@ discard:
        return 0;
 }
 
-static inline int dccp_invalid_packet(struct sk_buff *skb)
+EXPORT_SYMBOL_GPL(dccp_v4_do_rcv);
+
+int dccp_invalid_packet(struct sk_buff *skb)
 {
        const struct dccp_hdr *dh;
 
@@ -1075,29 +906,30 @@ static inline int dccp_invalid_packet(struct sk_buff *skb)
                return 1;
        }
 
-       /* If the header checksum is incorrect, drop packet and return */
-       if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr,
-                                   skb->nh.iph->daddr) < 0) {
-               LIMIT_NETDEBUG(KERN_WARNING "DCCP: header checksum is "
-                                           "incorrect\n");
-               return 1;
-       }
-
        return 0;
 }
 
+EXPORT_SYMBOL_GPL(dccp_invalid_packet);
+
 /* this is called when real data arrives */
 int dccp_v4_rcv(struct sk_buff *skb)
 {
        const struct dccp_hdr *dh;
        struct sock *sk;
-       int rc;
 
        /* Step 1: Check header basics: */
 
        if (dccp_invalid_packet(skb))
                goto discard_it;
 
+       /* If the header checksum is incorrect, drop packet and return */
+       if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr,
+                                   skb->nh.iph->daddr) < 0) {
+               LIMIT_NETDEBUG(KERN_WARNING "%s: incorrect header checksum\n",
+                              __FUNCTION__);
+               goto discard_it;
+       }
+
        dh = dccp_hdr(skb);
 
        DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(skb);
@@ -1153,28 +985,11 @@ int dccp_v4_rcv(struct sk_buff *skb)
                 goto do_time_wait;
        }
 
-       if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
-               dccp_pr_debug("xfrm4_policy_check failed\n");
+       if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_and_relse;
-       }
-
-        if (sk_filter(sk, skb, 0)) {
-               dccp_pr_debug("sk_filter failed\n");
-                goto discard_and_relse;
-       }
-
-       skb->dev = NULL;
-
-       bh_lock_sock(sk);
-       rc = 0;
-       if (!sock_owned_by_user(sk))
-               rc = dccp_v4_do_rcv(sk, skb);
-       else
-               sk_add_backlog(sk, skb);
-       bh_unlock_sock(sk);
+       nf_reset(skb);
 
-       sock_put(sk);
-       return rc;
+       return sk_receive_skb(sk, skb);
 
 no_dccp_socket:
        if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
@@ -1217,9 +1032,10 @@ struct inet_connection_sock_af_ops dccp_ipv4_af_ops = {
        .sockaddr_len   = sizeof(struct sockaddr_in),
 };
 
-static int dccp_v4_init_sock(struct sock *sk)
+int dccp_v4_init_sock(struct sock *sk)
 {
        struct dccp_sock *dp = dccp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
        static int dccp_ctl_socket_init = 1;
 
        dccp_options_init(&dp->dccps_options);
@@ -1259,10 +1075,11 @@ static int dccp_v4_init_sock(struct sock *sk)
                dccp_ctl_socket_init = 0;
 
        dccp_init_xmit_timers(sk);
-       inet_csk(sk)->icsk_rto = DCCP_TIMEOUT_INIT;
+       icsk->icsk_rto = DCCP_TIMEOUT_INIT;
        sk->sk_state = DCCP_CLOSED;
        sk->sk_write_space = dccp_write_space;
-       inet_csk(sk)->icsk_af_ops = &dccp_ipv4_af_ops;
+       icsk->icsk_af_ops = &dccp_ipv4_af_ops;
+       icsk->icsk_sync_mss = dccp_sync_mss;
        dp->dccps_mss_cache = 536;
        dp->dccps_role = DCCP_ROLE_UNDEFINED;
        dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
@@ -1270,7 +1087,9 @@ static int dccp_v4_init_sock(struct sock *sk)
        return 0;
 }
 
-static int dccp_v4_destroy_sock(struct sock *sk)
+EXPORT_SYMBOL_GPL(dccp_v4_init_sock);
+
+int dccp_v4_destroy_sock(struct sock *sk)
 {
        struct dccp_sock *dp = dccp_sk(sk);
 
@@ -1303,6 +1122,8 @@ static int dccp_v4_destroy_sock(struct sock *sk)
        return 0;
 }
 
+EXPORT_SYMBOL_GPL(dccp_v4_destroy_sock);
+
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
        kfree(inet_rsk(req)->opt);
@@ -1317,7 +1138,11 @@ static struct request_sock_ops dccp_request_sock_ops = {
        .send_reset     = dccp_v4_ctl_send_reset,
 };
 
-struct proto dccp_v4_prot = {
+static struct timewait_sock_ops dccp_timewait_sock_ops = {
+       .twsk_obj_size  = sizeof(struct inet_timewait_sock),
+};
+
+struct proto dccp_prot = {
        .name                   = "DCCP",
        .owner                  = THIS_MODULE,
        .close                  = dccp_close,
@@ -1331,7 +1156,7 @@ struct proto dccp_v4_prot = {
        .recvmsg                = dccp_recvmsg,
        .backlog_rcv            = dccp_v4_do_rcv,
        .hash                   = dccp_v4_hash,
-       .unhash                 = dccp_v4_unhash,
+       .unhash                 = dccp_unhash,
        .accept                 = inet_csk_accept,
        .get_port               = dccp_v4_get_port,
        .shutdown               = dccp_shutdown,
@@ -1340,5 +1165,7 @@ struct proto dccp_v4_prot = {
        .max_header             = MAX_DCCP_HEADER,
        .obj_size               = sizeof(struct dccp_sock),
        .rsk_prot               = &dccp_request_sock_ops,
-       .twsk_obj_size          = sizeof(struct inet_timewait_sock),
+       .twsk_prot              = &dccp_timewait_sock_ops,
 };
+
+EXPORT_SYMBOL_GPL(dccp_prot);