cfg80211: wext: don't display BSSID unless associated
[safe/jmp/linux-2.6] / net / ipv4 / ip_output.c
index d533a89..9fe5d7b 100644 (file)
@@ -95,7 +95,7 @@ int __ip_local_out(struct sk_buff *skb)
 
        iph->tot_len = htons(skb->len);
        ip_send_check(iph);
-       return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev,
+       return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev,
                       dst_output);
 }
 
@@ -118,7 +118,7 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb)
        __skb_pull(newskb, skb_network_offset(newskb));
        newskb->pkt_type = PACKET_LOOPBACK;
        newskb->ip_summed = CHECKSUM_UNNECESSARY;
-       WARN_ON(!newskb->dst);
+       WARN_ON(!skb_dst(newskb));
        netif_rx(newskb);
        return 0;
 }
@@ -140,7 +140,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
                          __be32 saddr, __be32 daddr, struct ip_options *opt)
 {
        struct inet_sock *inet = inet_sk(sk);
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct iphdr *iph;
 
        /* Build the IP header. */
@@ -176,15 +176,15 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
 
 static inline int ip_finish_output2(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct rtable *rt = (struct rtable *)dst;
        struct net_device *dev = dst->dev;
        unsigned int hh_len = LL_RESERVED_SPACE(dev);
 
-       if (rt->rt_type == RTN_MULTICAST)
-               IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTMCASTPKTS);
-       else if (rt->rt_type == RTN_BROADCAST)
-               IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTBCASTPKTS);
+       if (rt->rt_type == RTN_MULTICAST) {
+               IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len);
+       else if (rt->rt_type == RTN_BROADCAST)
+               IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTBCAST, skb->len);
 
        /* Be paranoid, rather than too clever. */
        if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
@@ -217,14 +217,14 @@ static inline int ip_skb_dst_mtu(struct sk_buff *skb)
        struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
 
        return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
-              skb->dst->dev->mtu : dst_mtu(skb->dst);
+              skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
 }
 
 static int ip_finish_output(struct sk_buff *skb)
 {
 #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
        /* Policy lookup after SNAT yielded a new policy */
-       if (skb->dst->xfrm != NULL) {
+       if (skb_dst(skb)->xfrm != NULL) {
                IPCB(skb)->flags |= IPSKB_REROUTED;
                return dst_output(skb);
        }
@@ -238,13 +238,13 @@ static int ip_finish_output(struct sk_buff *skb)
 int ip_mc_output(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct net_device *dev = rt->u.dst.dev;
 
        /*
         *      If the indicated interface is up and running, send the packet.
         */
-       IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTREQUESTS);
+       IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len);
 
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
@@ -296,9 +296,9 @@ int ip_mc_output(struct sk_buff *skb)
 
 int ip_output(struct sk_buff *skb)
 {
-       struct net_device *dev = skb->dst->dev;
+       struct net_device *dev = skb_dst(skb)->dev;
 
-       IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTREQUESTS);
+       IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len);
 
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
@@ -319,7 +319,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
        /* Skip all of this if the packet is already routed,
         * f.e. by something like SCTP.
         */
-       rt = skb->rtable;
+       rt = skb_rtable(skb);
        if (rt != NULL)
                goto packet_routed;
 
@@ -340,6 +340,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
                                                        .saddr = inet->saddr,
                                                        .tos = RT_CONN_FLAGS(sk) } },
                                            .proto = sk->sk_protocol,
+                                           .flags = inet_sk_flowi_flags(sk),
                                            .uli_u = { .ports =
                                                       { .sport = inet->sport,
                                                         .dport = inet->dport } } };
@@ -354,7 +355,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
                }
                sk_setup_caps(sk, &rt->u.dst);
        }
-       skb->dst = dst_clone(&rt->u.dst);
+       skb_dst_set(skb, dst_clone(&rt->u.dst));
 
 packet_routed:
        if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
@@ -400,8 +401,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->pkt_type = from->pkt_type;
        to->priority = from->priority;
        to->protocol = from->protocol;
-       dst_release(to->dst);
-       to->dst = dst_clone(from->dst);
+       skb_dst_drop(to);
+       skb_dst_set(to, dst_clone(skb_dst(from)));
        to->dev = from->dev;
        to->mark = from->mark;
 
@@ -429,7 +430,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
  *     single device frame, and queue such a frame for sending.
  */
 
-int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
        struct iphdr *iph;
        int raw = 0;
@@ -439,7 +440,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
        unsigned int mtu, hlen, left, len, ll_rs, pad;
        int offset;
        __be16 not_last_frag;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        int err = 0;
 
        dev = rt->u.dst.dev;
@@ -473,7 +474,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
         * LATER: this step can be merged to real generation of fragments,
         * we can switch to copy when see the first bad fragment.
         */
-       if (skb_shinfo(skb)->frag_list) {
+       if (skb_has_frags(skb)) {
                struct sk_buff *frag;
                int first_len = skb_pagelen(skb);
                int truesizes = 0;
@@ -484,7 +485,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
                    skb_cloned(skb))
                        goto slow_path;
 
-               for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
+               skb_walk_frags(skb, frag) {
                        /* Correct geometry. */
                        if (frag->len > mtu ||
                            ((frag->len & 7) && frag->next) ||
@@ -497,7 +498,6 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
 
                        BUG_ON(frag->sk);
                        if (skb->sk) {
-                               sock_hold(skb->sk);
                                frag->sk = skb->sk;
                                frag->destructor = sock_wfree;
                                truesizes += frag->truesize;
@@ -509,7 +509,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
                err = 0;
                offset = 0;
                frag = skb_shinfo(skb)->frag_list;
-               skb_shinfo(skb)->frag_list = NULL;
+               skb_frag_list_init(skb);
                skb->data_len = first_len - skb_headlen(skb);
                skb->truesize -= truesizes;
                skb->len = first_len;
@@ -719,7 +719,7 @@ static inline int ip_ufo_append_data(struct sock *sk,
                        int getfrag(void *from, char *to, int offset, int len,
                               int odd, struct sk_buff *skb),
                        void *from, int length, int hh_len, int fragheaderlen,
-                       int transhdrlen, int mtu,unsigned int flags)
+                       int transhdrlen, int mtu, unsigned int flags)
 {
        struct sk_buff *skb;
        int err;
@@ -740,7 +740,7 @@ static inline int ip_ufo_append_data(struct sock *sk,
                skb_reserve(skb, hh_len);
 
                /* create space for UDP/IP header */
-               skb_put(skb,fragheaderlen + transhdrlen);
+               skb_put(skb, fragheaderlen + transhdrlen);
 
                /* initialize network header pointer */
                skb_reset_network_header(skb);
@@ -777,7 +777,7 @@ int ip_append_data(struct sock *sk,
                   int getfrag(void *from, char *to, int offset, int len,
                               int odd, struct sk_buff *skb),
                   void *from, int length, int transhdrlen,
-                  struct ipcm_cookie *ipc, struct rtable *rt,
+                  struct ipcm_cookie *ipc, struct rtable **rtp,
                   unsigned int flags)
 {
        struct inet_sock *inet = inet_sk(sk);
@@ -792,6 +792,7 @@ int ip_append_data(struct sock *sk,
        int offset = 0;
        unsigned int maxfraglen, fragheaderlen;
        int csummode = CHECKSUM_NONE;
+       struct rtable *rt;
 
        if (flags&MSG_PROBE)
                return 0;
@@ -811,7 +812,13 @@ int ip_append_data(struct sock *sk,
                        inet->cork.flags |= IPCORK_OPT;
                        inet->cork.addr = ipc->addr;
                }
-               dst_hold(&rt->u.dst);
+               rt = *rtp;
+               if (unlikely(!rt))
+                       return -EFAULT;
+               /*
+                * We steal reference to this route, caller should not release it
+                */
+               *rtp = NULL;
                inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ?
                                            rt->u.dst.dev->mtu :
                                            dst_mtu(rt->u.dst.path);
@@ -929,6 +936,10 @@ alloc_new_skb:
                                                           sk->sk_allocation);
                                if (unlikely(skb == NULL))
                                        err = -ENOBUFS;
+                               else
+                                       /* only the initial fragment is
+                                          time stamped */
+                                       ipc->shtx.flags = 0;
                        }
                        if (skb == NULL)
                                goto error;
@@ -939,6 +950,7 @@ alloc_new_skb:
                        skb->ip_summed = csummode;
                        skb->csum = 0;
                        skb_reserve(skb, hh_len);
+                       *skb_tx(skb) = ipc->shtx;
 
                        /*
                         *      Find where to start putting bytes.
@@ -1233,7 +1245,6 @@ int ip_push_pending_frames(struct sock *sk)
                skb->len += tmp_skb->len;
                skb->data_len += tmp_skb->len;
                skb->truesize += tmp_skb->truesize;
-               __sock_put(tmp_skb->sk);
                tmp_skb->destructor = NULL;
                tmp_skb->sk = NULL;
        }
@@ -1278,7 +1289,12 @@ int ip_push_pending_frames(struct sock *sk)
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
-       skb->dst = dst_clone(&rt->u.dst);
+       /*
+        * Steal rt from cork.dst to avoid a pair of atomic_inc/atomic_dec
+        * on dst refcount
+        */
+       inet->cork.dst = NULL;
+       skb_dst_set(skb, &rt->u.dst);
 
        if (iph->protocol == IPPROTO_ICMP)
                icmp_out_count(net, ((struct icmphdr *)
@@ -1288,7 +1304,7 @@ int ip_push_pending_frames(struct sock *sk)
        err = ip_local_out(skb);
        if (err) {
                if (err > 0)
-                       err = inet->recverr ? net_xmit_errno(err) : 0;
+                       err = net_xmit_errno(err);
                if (err)
                        goto error;
        }
@@ -1346,13 +1362,14 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
        } replyopts;
        struct ipcm_cookie ipc;
        __be32 daddr;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
 
        if (ip_options_echo(&replyopts.opt, skb))
                return;
 
        daddr = ipc.addr = rt->rt_src;
        ipc.opt = NULL;
+       ipc.shtx.flags = 0;
 
        if (replyopts.opt.optlen) {
                ipc.opt = &replyopts.opt;
@@ -1371,7 +1388,8 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
                                    .uli_u = { .ports =
                                               { .sport = tcp_hdr(skb)->dest,
                                                 .dport = tcp_hdr(skb)->source } },
-                                   .proto = sk->sk_protocol };
+                                   .proto = sk->sk_protocol,
+                                   .flags = ip_reply_arg_flowi_flags(arg) };
                security_skb_classify_flow(skb, &fl);
                if (ip_route_output_key(sock_net(sk), &rt, &fl))
                        return;
@@ -1389,7 +1407,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
        sk->sk_protocol = ip_hdr(skb)->protocol;
        sk->sk_bound_dev_if = arg->bound_dev_if;
        ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0,
-                      &ipc, rt, MSG_DONTWAIT);
+                      &ipc, &rt, MSG_DONTWAIT);
        if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
                if (arg->csumoffset >= 0)
                        *((__sum16 *)skb_transport_header(skb) +