static int gannet_xmit(struct sk_buff *skb, struct net_device *dev) { struct gannet_private *p = netdev_priv(dev); int ret; struct gannet_work_struct *work; if (NULL == ipip_hdr(skb)) { printk(KERN_WARNING "gannet dropping packet, no IP header\n"); dev_kfree_skb(skb); return NET_XMIT_DROP; } if (skb->len < (sizeof(struct ethhdr) + sizeof(struct iphdr))) { printk(KERN_WARNING "gannet: Packet too short (%i bytes)\n", skb->len); return 0; } if (gannet_wq) { work = kmalloc(sizeof(struct gannet_work_struct), GFP_ATOMIC); if (work) { INIT_WORK((struct work_struct *)work, gannet_wq_func); work->skb = skb; work->p = p; ret = queue_work(gannet_wq, (struct work_struct *)work); } else { printk(KERN_WARNING "gannet dropping packet, \ cannot allocate work queue item\n"); } } return 0; }
static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) { int err = -EINVAL; if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) goto out; if (!pskb_may_pull(skb, sizeof(struct iphdr))) goto out; if (skb_cloned(skb) && (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) goto out; if (x->props.flags & XFRM_STATE_DECAP_DSCP) ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb)); if (!(x->props.flags & XFRM_STATE_NOECN)) ipip_ecn_decapsulate(skb); skb_reset_network_header(skb); skb_mac_header_rebuild(skb); err = 0; out: return err; }
static inline void ipip_ecn_decapsulate(struct sk_buff *skb) { struct iphdr *inner_iph = ipip_hdr(skb); if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) IP_ECN_set_ce(inner_iph); }
static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) { struct xfrm_tunnel *handler; int err = -EINVAL; if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) goto out; if (!pskb_may_pull(skb, sizeof(struct iphdr))) goto out; for_each_input_rcu(rcv_notify_handlers, handler) handler->handler(skb); err = skb_unclone(skb, GFP_ATOMIC); if (err) goto out; if (x->props.flags & XFRM_STATE_DECAP_DSCP) ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb)); if (!(x->props.flags & XFRM_STATE_NOECN)) ipip_ecn_decapsulate(skb); skb_reset_network_header(skb); skb_mac_header_rebuild(skb); err = 0; out: return err; }
static int niit_xmit(struct sk_buff *skb, struct net_device *dev) { struct niit_tunnel *tunnel = (struct niit_tunnel *) netdev_priv(tunnel4_dev); struct ethhdr *ethhead; struct iphdr *iph4; struct ipv6hdr *iph6; struct net_device_stats *stats; struct rt6_info *rt6; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ __u8 nexthdr; /* IPv6 next header */ u32 delta; /* calc space inside skb */ unsigned int max_headroom; /* The extra header space needed */ struct in6_addr s6addr; struct in6_addr d6addr; /* * all IPv4 (includes icmp) will be encapsulated. * IPv6 ICMPs for IPv4 encapsulated data should be translated * */ if (skb->protocol == htons(ETH_P_IP)) { stats = &tunnel4_dev->stats; PDEBUG("niit: skb->proto = iph4 \n"); iph4 = ip_hdr(skb); s6addr.in6_u.u6_addr32[0] = tunnel->ipv6prefix_1; s6addr.in6_u.u6_addr32[1] = tunnel->ipv6prefix_2; s6addr.in6_u.u6_addr32[2] = tunnel->ipv6prefix_3; s6addr.in6_u.u6_addr32[3] = iph4->saddr; d6addr.in6_u.u6_addr32[0] = tunnel->ipv6prefix_1; d6addr.in6_u.u6_addr32[1] = tunnel->ipv6prefix_2; d6addr.in6_u.u6_addr32[2] = tunnel->ipv6prefix_3; d6addr.in6_u.u6_addr32[3] = iph4->daddr; PDEBUG("niit: ipv4: saddr: %x%x%x%x \n niit: ipv4: daddr %x%x%x%x \n", s6addr.in6_u.u6_addr32[0], s6addr.in6_u.u6_addr32[1], s6addr.in6_u.u6_addr32[2], s6addr.in6_u.u6_addr32[3], d6addr.in6_u.u6_addr32[0], d6addr.in6_u.u6_addr32[1], d6addr.in6_u.u6_addr32[2], d6addr.in6_u.u6_addr32[3]); if ((rt6 = rt6_lookup(dev_net(tunnel4_dev), &d6addr, &s6addr, (tunnel4_dev)->iflink, 0)) == NULL) { stats->tx_carrier_errors++; goto tx_error_icmp; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) tdev = rt6->u.dst.dev; dst_release(&rt6->u.dst); #else tdev = rt6->dst.dev; dst_release(&rt6->dst); #endif if (tdev == dev) { PDEBUG("niit: recursion detected todev = dev \n"); stats->collisions++; goto tx_error; } /* old MTU check */ /* * Resize the buffer to push our ipv6 head into */ max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr); if (skb_headroom(skb) < max_headroom || skb_shared(skb) || (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); if (!new_skb) { stats->tx_dropped++; dev_kfree_skb(skb); tunnel->recursion--; return 0; } if (skb->sk) skb_set_owner_w(new_skb, skb->sk); dev_kfree_skb(skb); skb = new_skb; iph4 = ip_hdr(skb); } delta = skb_network_header(skb) - skb->data; /* make our skb space best fit */ if (delta < sizeof(struct ipv6hdr)) { iph6 = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr) - delta); PDEBUG("niit: iph6 < 0 skb->len %x \n", skb->len); } else if (delta > sizeof(struct ipv6hdr)) { iph6 = (struct ipv6hdr*) skb_pull(skb, delta - sizeof(struct ipv6hdr)); PDEBUG("niit: iph6 > 0 skb->len %x \n", skb->len); } else { iph6 = (struct ipv6hdr*) skb->data; PDEBUG("niit: iph6 = 0 skb->len %x \n", skb->len); } /* how the package should look like : * skb->network_header = iph6 * skb->transport_header = iph4; */ skb->transport_header = skb->network_header; /* we say skb->transport_header = iph4; */ skb_reset_network_header(skb); /* now -> we reset the network header to skb->data which is our ipv6 paket */ skb_reset_mac_header(skb); skb->mac_header = skb->network_header - sizeof(struct ethhdr); skb->mac_len = sizeof(struct ethhdr); /* add a dummy ethhdr to use correct interface linktype */ ethhead = eth_hdr(skb); memcpy(ethhead->h_dest, tunnel4_dev->dev_addr, ETH_ALEN); memcpy(ethhead->h_source, tunnel4_dev->dev_addr, ETH_ALEN); ethhead->h_proto = htons(ETH_P_IPV6); /* prepare to send it again */ IPCB(skb)->flags = 0; skb->protocol = htons(ETH_P_IPV6); skb->pkt_type = PACKET_HOST; skb->dev = tunnel4_dev; skb_dst_drop(skb); /* install v6 header */ memset(iph6, 0, sizeof(struct ipv6hdr)); iph6->version = 6; iph6->payload_len = iph4->tot_len; iph6->hop_limit = iph4->ttl; iph6->nexthdr = IPPROTO_IPIP; memcpy(&(iph6->saddr), &s6addr, sizeof(struct in6_addr)); memcpy(&(iph6->daddr), &d6addr, sizeof(struct in6_addr)); nf_reset(skb); netif_rx(skb); tunnel->recursion--; } else if (skb->protocol == htons(ETH_P_IPV6)) { /* got a ipv6-package and need to translate it back to ipv4 */ __be32 s4addr; __be32 d4addr; __u8 hoplimit; stats = &tunnel6_dev->stats; PDEBUG("niit: skb->proto = iph6 \n"); iph6 = ipv6_hdr(skb); if (!iph6) { PDEBUG("niit: cant find iph6 \n"); goto tx_error; } /* IPv6 to IPv4 */ hoplimit = iph6->hop_limit; /* check against our prefix which all packages must have */ if (iph6->daddr.s6_addr32[0] != tunnel->ipv6prefix_1 || iph6->daddr.s6_addr32[1] != tunnel->ipv6prefix_2 || iph6->daddr.s6_addr32[2] != tunnel->ipv6prefix_3) { PDEBUG("niit: xmit ipv6(): Dst addr haven't our previx addr: %x%x%x%x, packet dropped.\n", iph6->daddr.s6_addr32[0], iph6->daddr.s6_addr32[1], iph6->daddr.s6_addr32[2], iph6->daddr.s6_addr32[3]); goto tx_error; } s4addr = iph6->saddr.s6_addr32[3]; d4addr = iph6->daddr.s6_addr32[3]; nexthdr = iph6->nexthdr; /* TODO nexthdr handle */ /* while(nexthdr != IPPROTO_IPIP) { } */ if(nexthdr != IPPROTO_IPIP) { PDEBUG("niit: cant handle hdrtype : %x.\n", nexthdr); goto tx_error; } iph4 = ipip_hdr(skb); /* TODO: fix the check for a valid route */ /* { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = d4addr, .saddr = s4addr, .tos = RT_TOS(iph4->tos) } }, .oif = tunnel_dev->iflink, .proto = iph4->protocol }; if (ip_route_output_key(dev_net(dev), &rt, &fl)) { PDEBUG("niit : ip route not found \n"); stats->tx_carrier_errors++; goto tx_error_icmp; } } tdev = rt->u.dst.dev; if (tdev == tunnel_dev) { PDEBUG("niit : tdev == tunnel_dev \n"); ip_rt_put(rt); stats->collisions++; goto tx_error; } if (iph4->frag_off) mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); else mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; if (mtu < 68) { PDEBUG("niit : mtu < 68 \n"); stats->collisions++; ip_rt_put(rt); goto tx_error; } if (iph4->daddr && skb_dst(skb)) skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); */ /* if (skb->len > mtu) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); ip_rt_put(rt); goto tx_error; } */ /* * check if we can reuse our skb_buff */ if (skb_shared(skb) || (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { struct sk_buff *new_skb = skb_realloc_headroom(skb, skb_headroom(skb)); if (!new_skb) { stats->tx_dropped++; dev_kfree_skb(skb); tunnel->recursion--; return 0; } if (skb->sk) skb_set_owner_w(new_skb, skb->sk); dev_kfree_skb(skb); skb = new_skb; iph6 = ipv6_hdr(skb); iph4 = ipip_hdr(skb); } delta = skb_transport_header(skb) - skb->data; skb_pull(skb, delta); /* our paket come with ... */ /* skb->network_header iph6; */ /* skb->transport_header iph4; */ skb->network_header = skb->transport_header; /* we say skb->network_header = iph4; */ skb_set_transport_header(skb, sizeof(struct iphdr)); skb->mac_header = skb->network_header - sizeof(struct ethhdr); skb->mac_len = sizeof(struct ethhdr); /* add a dummy ethhdr to use correct interface linktype */ ethhead = eth_hdr(skb); memcpy(ethhead->h_dest, tunnel6_dev->dev_addr, ETH_ALEN); memcpy(ethhead->h_source, tunnel6_dev->dev_addr, ETH_ALEN); ethhead->h_proto = htons(ETH_P_IP); /* prepare to send it again */ IPCB(skb)->flags = 0; skb->protocol = htons(ETH_P_IP); skb->pkt_type = PACKET_HOST; skb->dev = tunnel6_dev; skb_dst_drop(skb); /* TODO: set iph4->ttl = hoplimit and recalc the checksum ! */ /* sending */ nf_reset(skb); netif_rx(skb); tunnel->recursion--; } else { stats = &tunnel6_dev->stats; PDEBUG("niit: unknown direction %x \n", skb->protocol); goto tx_error; /* drop */ } return 0; tx_error_icmp: dst_link_failure(skb); PDEBUG("niit: tx_error_icmp\n"); tx_error: PDEBUG("niit: tx_error\n"); stats->tx_errors++; dev_kfree_skb(skb); tunnel->recursion--; return 0; }