* Fixes:
* Alan Cox : Missing nonblock feature in ip_build_xmit.
* Mike Kilburn : htons() missing in ip_build_xmit.
* Fixes:
* Alan Cox : Missing nonblock feature in ip_build_xmit.
* Mike Kilburn : htons() missing in ip_build_xmit.
* some redundant tests.
* Vitaly E. Lavrov : Transparent proxy revived after year coma.
* Andi Kleen : Replace ip_reply with ip_send_reply.
* some redundant tests.
* Vitaly E. Lavrov : Transparent proxy revived after year coma.
* Andi Kleen : Replace ip_reply with ip_send_reply.
- * Andi Kleen : Split fast and slow ip_build_xmit path
- * for decreased register pressure on x86
- * and more readibility.
+ * Andi Kleen : Split fast and slow ip_build_xmit path
+ * for decreased register pressure on x86
+ * and more readibility.
* Marc Boucher : When call_out_firewall returns FW_QUEUE,
* silently drop skb instead of failing with -EPERM.
* Detlev Wengorz : Copy protocol for fragments.
* Marc Boucher : When call_out_firewall returns FW_QUEUE,
* silently drop skb instead of failing with -EPERM.
* Detlev Wengorz : Copy protocol for fragments.
/* dev_loopback_xmit for use with netfilter. */
static int ip_dev_loopback_xmit(struct sk_buff *newskb)
{
/* dev_loopback_xmit for use with netfilter. */
static int ip_dev_loopback_xmit(struct sk_buff *newskb)
{
- newskb->mac.raw = newskb->data;
- __skb_pull(newskb, newskb->nh.raw - newskb->data);
+ skb_reset_mac_header(newskb);
+ __skb_pull(newskb, skb_network_offset(newskb));
- if (opt)
- iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr) + opt->optlen);
- else
- iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr));
-
+ skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
+ skb_reset_network_header(skb);
+ iph = ip_hdr(skb);
iph->protocol = sk->sk_protocol;
iph->tot_len = htons(skb->len);
ip_select_ident(iph, &rt->u.dst, sk);
iph->protocol = sk->sk_protocol;
iph->tot_len = htons(skb->len);
ip_select_ident(iph, &rt->u.dst, sk);
/* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
struct sk_buff *skb2;
/* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
struct sk_buff *skb2;
+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);
+}
+
static inline int ip_finish_output(struct sk_buff *skb)
{
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
static inline int ip_finish_output(struct sk_buff *skb)
{
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
return ip_fragment(skb, ip_finish_output2);
else
return ip_finish_output2(skb);
return ip_fragment(skb, ip_finish_output2);
else
return ip_finish_output2(skb);
struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
if (newskb)
NF_HOOK(PF_INET, NF_IP_POST_ROUTING, newskb, NULL,
struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
if (newskb)
NF_HOOK(PF_INET, NF_IP_POST_ROUTING, newskb, NULL,
skb->protocol = htons(ETH_P_IP);
return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
skb->protocol = htons(ETH_P_IP);
return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
iph->tot_len = htons(skb->len);
if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
iph->tot_len = htons(skb->len);
if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
-#ifdef CONFIG_NETFILTER
- /* Connection association is same as pre-frag packet */
- nf_conntrack_put(to->nfct);
- to->nfct = from->nfct;
- nf_conntrack_get(to->nfct);
- to->nfctinfo = from->nfctinfo;
+ nf_copy(to, from);
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+ to->nf_trace = from->nf_trace;
+#endif
if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
IP_INC_STATS(IPSTATS_MIB_FRAGFAILS);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
IP_INC_STATS(IPSTATS_MIB_FRAGFAILS);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
- frag->h.raw = frag->data;
- frag->nh.raw = __skb_push(frag, hlen);
- memcpy(frag->nh.raw, iph, hlen);
- iph = frag->nh.iph;
+ skb_reset_transport_header(frag);
+ __skb_push(frag, hlen);
+ skb_reset_network_header(frag);
+ memcpy(skb_network_header(frag), iph, hlen);
+ iph = ip_hdr(frag);
iph->tot_len = htons(frag->len);
ip_copy_metadata(frag, skb);
if (offset == 0)
iph->tot_len = htons(frag->len);
ip_copy_metadata(frag, skb);
if (offset == 0)
ip_copy_metadata(skb2, skb);
skb_reserve(skb2, ll_rs);
skb_put(skb2, len + hlen);
ip_copy_metadata(skb2, skb);
skb_reserve(skb2, ll_rs);
skb_put(skb2, len + hlen);
- if (skb_copy_bits(skb, ptr, skb2->h.raw, len))
+ if (skb_copy_bits(skb, ptr, skb_transport_header(skb2), len))
iph->frag_off = htons((offset >> 3));
/* ANK: dirty, but effective trick. Upgrade options only if
iph->frag_off = htons((offset >> 3));
/* ANK: dirty, but effective trick. Upgrade options only if
skb_put(skb,fragheaderlen + transhdrlen);
/* initialize network header pointer */
skb_put(skb,fragheaderlen + transhdrlen);
/* initialize network header pointer */
* from many pieces of data. Each pieces will be holded on the socket
* until ip_push_pending_frames() is called. Each piece can be a page
* or non-page data.
* from many pieces of data. Each pieces will be holded on the socket
* until ip_push_pending_frames() is called. Each piece can be a page
* or non-page data.
* Not only UDP, other transport protocols - e.g. raw sockets - can use
* this interface potentially.
*
* Not only UDP, other transport protocols - e.g. raw sockets - can use
* this interface potentially.
*
alloclen + hh_len + 15,
(flags & MSG_DONTWAIT), &err);
} else {
skb = NULL;
if (atomic_read(&sk->sk_wmem_alloc) <=
2 * sk->sk_sndbuf)
alloclen + hh_len + 15,
(flags & MSG_DONTWAIT), &err);
} else {
skb = NULL;
if (atomic_read(&sk->sk_wmem_alloc) <=
2 * sk->sk_sndbuf)
alloclen + hh_len + 15, 1,
sk->sk_allocation);
if (unlikely(skb == NULL))
alloclen + hh_len + 15, 1,
sk->sk_allocation);
if (unlikely(skb == NULL))
* Find where to start putting bytes.
*/
data = skb_put(skb, fraglen);
* Find where to start putting bytes.
*/
data = skb_put(skb, fraglen);
- if (getfrag(from, skb_put(skb, copy),
+ if (getfrag(from, skb_put(skb, copy),
offset, copy, off, skb) < 0) {
__skb_trim(skb, off);
err = -EFAULT;
offset, copy, off, skb) < 0) {
__skb_trim(skb, off);
err = -EFAULT;
- skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
+ skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
- data = skb_put(skb, fragheaderlen + fraggap);
- skb->nh.iph = iph = (struct iphdr *)data;
- data += fragheaderlen;
- skb->h.raw = data;
-
+ skb_put(skb, fragheaderlen + fraggap);
+ skb_reset_network_header(skb);
+ skb->transport_header = (skb->network_header +
+ fragheaderlen);
skb_prev->csum = csum_sub(skb_prev->csum,
skb->csum);
pskb_trim_unique(skb_prev, maxfraglen);
skb_prev->csum = csum_sub(skb_prev->csum,
skb->csum);
pskb_trim_unique(skb_prev, maxfraglen);
- if (skb->data < skb->nh.raw)
- __skb_pull(skb, skb->nh.raw - skb->data);
+ if (skb->data < skb_network_header(skb))
+ __skb_pull(skb, skb_network_offset(skb));
* to fragment the frame generated here. No matter, what transforms
* how transforms change size of the packet, it will come out.
*/
* to fragment the frame generated here. No matter, what transforms
* how transforms change size of the packet, it will come out.
*/
skb->local_df = 1;
/* DF bit is set when we want to see DF on outgoing frames.
* If local_df is set too, we still allow to fragment this frame
* locally. */
skb->local_df = 1;
/* DF bit is set when we want to see DF on outgoing frames.
* If local_df is set too, we still allow to fragment this frame
* locally. */
(skb->len <= dst_mtu(&rt->u.dst) &&
ip_dont_fragment(sk, &rt->u.dst)))
df = htons(IP_DF);
(skb->len <= dst_mtu(&rt->u.dst) &&
ip_dont_fragment(sk, &rt->u.dst)))
df = htons(IP_DF);
- err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
-static int ip_reply_glue_bits(void *dptr, char *to, int offset,
+static int ip_reply_glue_bits(void *dptr, char *to, int offset,
int len, int odd, struct sk_buff *skb)
{
__wsum csum;
csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0);
skb->csum = csum_block_add(skb->csum, csum, odd);
int len, int odd, struct sk_buff *skb)
{
__wsum csum;
csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0);
skb->csum = csum_block_add(skb->csum, csum, odd);
* Generic function to send a packet as reply to another packet.
* Used to send TCP resets so far. ICMP should use this function too.
*
* Generic function to send a packet as reply to another packet.
* Used to send TCP resets so far. ICMP should use this function too.
*
- { .sport = skb->h.th->dest,
- .dport = skb->h.th->source } },
+ { .sport = tcp_hdr(skb)->dest,
+ .dport = tcp_hdr(skb)->source } },
.proto = sk->sk_protocol };
security_skb_classify_flow(skb, &fl);
if (ip_route_output_key(&rt, &fl))
.proto = sk->sk_protocol };
security_skb_classify_flow(skb, &fl);
if (ip_route_output_key(&rt, &fl))
ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0,
&ipc, rt, MSG_DONTWAIT);
if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
if (arg->csumoffset >= 0)
ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0,
&ipc, rt, MSG_DONTWAIT);
if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
if (arg->csumoffset >= 0)