static void ipcomp_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct iphdr *iph, *top_iph; iph = skb->nh.iph; top_iph = (struct iphdr *)skb_push(skb, sizeof(struct iphdr)); top_iph->ihl = 5; top_iph->version = 4; top_iph->tos = iph->tos; top_iph->tot_len = htons(skb->len); if (!(iph->frag_off&htons(IP_DF))) { #ifdef NETIF_F_TSO __ip_select_ident(top_iph, dst, 0); #else __ip_select_ident(top_iph, dst); #endif } top_iph->ttl = iph->ttl; top_iph->check = 0; top_iph->saddr = x->props.saddr.a4; top_iph->daddr = x->id.daddr.a4; top_iph->frag_off = iph->frag_off&~htons(IP_MF|IP_OFFSET); memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); skb->nh.raw = skb->data; }
static int ipip_output(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; struct iphdr *iph, *top_iph; int tos, err; if ((err = xfrm4_tunnel_check_size(skb)) != 0) goto error_nolock; iph = skb->nh.iph; spin_lock_bh(&x->lock); tos = iph->tos; top_iph = (struct iphdr *) skb_push(skb, x->props.header_len); top_iph->ihl = 5; top_iph->version = 4; top_iph->tos = INET_ECN_encapsulate(tos, iph->tos); top_iph->tot_len = htons(skb->len); top_iph->frag_off = iph->frag_off & ~htons(IP_MF|IP_OFFSET); if (!(iph->frag_off & htons(IP_DF))) { #ifdef NETIF_F_TSO __ip_select_ident(top_iph, dst, 0); #else __ip_select_ident(top_iph, dst); #endif } top_iph->ttl = iph->ttl; top_iph->protocol = IPPROTO_IPIP; top_iph->check = 0; top_iph->saddr = x->props.saddr.a4; top_iph->daddr = x->id.daddr.a4; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); ip_send_check(top_iph); skb->nh.raw = skb->data; x->curlft.bytes += skb->len; x->curlft.packets++; spin_unlock_bh(&x->lock); if ((skb->dst = dst_pop(dst)) == NULL) { kfree_skb(skb); err = -EHOSTUNREACH; goto error_nolock; } return NET_XMIT_BYPASS; error_nolock: kfree_skb(skb); return err; }
/* * Add an ip header to a skbuff and send it out. * */ int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk, __be32 saddr, __be32 daddr, struct ip_options_rcu *opt) { struct inet_sock *inet = inet_sk(sk); struct rtable *rt = skb_rtable(skb); struct net *net = sock_net(sk); struct iphdr *iph; /* Build the IP header. */ skb_push(skb, sizeof(struct iphdr) + (opt ? opt->opt.optlen : 0)); skb_reset_network_header(skb); iph = ip_hdr(skb); iph->version = 4; iph->ihl = 5; iph->tos = inet->tos; iph->ttl = ip_select_ttl(inet, &rt->dst); iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr); iph->saddr = saddr; iph->protocol = sk->sk_protocol; if (ip_dont_fragment(sk, &rt->dst)) { iph->frag_off = htons(IP_DF); iph->id = 0; } else { iph->frag_off = 0; __ip_select_ident(net, iph, 1); } if (opt && opt->opt.optlen) { iph->ihl += opt->opt.optlen>>2; ip_options_build(skb, &opt->opt, daddr, rt, 0); }
/* Add encapsulation header. * * The top IP header will be constructed per RFC 2401. The following fields * in it shall be filled in by x->type->output: * tot_len * check * * On exit, skb->h will be set to the start of the payload to be processed * by x->type->output and skb->nh will be set to the top IP header. */ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct xfrm_dst *xdst = (struct xfrm_dst*)dst; struct iphdr *iph, *top_iph; int flags; iph = skb->nh.iph; skb->h.ipiph = iph; skb->nh.raw = skb_push(skb, x->props.header_len); top_iph = skb->nh.iph; top_iph->ihl = 5; top_iph->version = 4; flags = x->props.flags; /* DS disclosed */ if (xdst->route->ops->family == AF_INET) { top_iph->protocol = IPPROTO_IPIP; top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? 0 : (iph->frag_off & htons(IP_DF)); } #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) else { struct ipv6hdr *ipv6h = (struct ipv6hdr*)iph; top_iph->protocol = IPPROTO_IPV6; top_iph->tos = INET_ECN_encapsulate(iph->tos, ipv6_get_dsfield(ipv6h)); top_iph->frag_off = 0; } #endif if (flags & XFRM_STATE_NOECN) IP_ECN_clear(top_iph); if (!top_iph->frag_off) __ip_select_ident(top_iph, dst->child, 0); top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); top_iph->saddr = x->props.saddr.a4; top_iph->daddr = x->id.daddr.a4; skb->protocol = htons(ETH_P_IP); memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); return 0; }
/* Add encapsulation header. * * In transport mode, the IP header will be moved forward to make space * for the encapsulation header. * * In tunnel mode, the top IP header will be constructed per RFC 2401. * The following fields in it shall be filled in by x->type->output: * tot_len * check * * On exit, skb->h will be set to the start of the payload to be processed * by x->type->output and skb->nh will be set to the top IP header. */ static void xfrm4_encap(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; struct iphdr *iph, *top_iph; int flags; iph = skb->nh.iph; skb->h.ipiph = iph; skb->nh.raw = skb_push(skb, x->props.header_len); top_iph = skb->nh.iph; if (!x->props.mode) { skb->h.raw += iph->ihl*4; memmove(top_iph, iph, iph->ihl*4); return; } top_iph->ihl = 5; top_iph->version = 4; /* DS disclosed */ top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); flags = x->props.flags; if (flags & XFRM_STATE_NOECN) IP_ECN_clear(top_iph); top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? 0 : (iph->frag_off & htons(IP_DF)); if (!top_iph->frag_off) __ip_select_ident(top_iph, dst, 0); top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); top_iph->saddr = x->props.saddr.a4; top_iph->daddr = x->id.daddr.a4; top_iph->protocol = IPPROTO_IPIP; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); }