/* When forwarding a packet, we must ensure that we've got enough headroom * for the encapsulation packet in the skb. This also gives us an * opportunity to figure out what the payload_len, dsfield, ttl, and df * values should be, so that we won't need to look at the old ip header * again */ static struct sk_buff * ip_vs_prepare_tunneled_skb(struct sk_buff *skb, int skb_af, unsigned int max_headroom, __u8 *next_protocol, __u32 *payload_len, __u8 *dsfield, __u8 *ttl, __be16 *df) { struct sk_buff *new_skb = NULL; struct iphdr *old_iph = NULL; #ifdef CONFIG_IP_VS_IPV6 struct ipv6hdr *old_ipv6h = NULL; #endif ip_vs_drop_early_demux_sk(skb); if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) { new_skb = skb_realloc_headroom(skb, max_headroom); if (!new_skb) goto error; if (skb->sk) skb_set_owner_w(new_skb, skb->sk); consume_skb(skb); skb = new_skb; } #ifdef CONFIG_IP_VS_IPV6 if (skb_af == AF_INET6) { old_ipv6h = ipv6_hdr(skb); *next_protocol = IPPROTO_IPV6; if (payload_len) *payload_len = ntohs(old_ipv6h->payload_len) + sizeof(*old_ipv6h); *dsfield = ipv6_get_dsfield(old_ipv6h); *ttl = old_ipv6h->hop_limit; if (df) *df = 0; } else #endif { old_iph = ip_hdr(skb); /* Copy DF, reset fragment offset and MF */ if (df) *df = (old_iph->frag_off & htons(IP_DF)); *next_protocol = IPPROTO_IPIP; /* fix old IP header checksum */ ip_send_check(old_iph); *dsfield = ipv4_get_dsfield(old_iph); *ttl = old_iph->ttl; if (payload_len) *payload_len = ntohs(old_iph->tot_len); } return skb; error: kfree_skb(skb); return ERR_PTR(-ENOMEM); }
HYFI_MC_STATIC unsigned int mc_pre_routing_hook(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int(*okfn)(struct sk_buff *)) { struct hyfi_net_bridge *hyfi_br = hyfi_bridge_get_by_dev(in); struct mc_struct *mc = MC_DEV(hyfi_br); struct ethhdr *eh = eth_hdr(skb); struct net_bridge_port *port; u8 dscp; if (!mc || skb->pkt_type != PACKET_HOST || (port = hyfi_br_port_get(in)) == NULL) goto out; dscp = MC_DSCP(mc->dscp) & (~INET_ECN_MASK); switch (ntohs(skb->protocol)) { case ETH_P_IP: { const struct iphdr *iph = ip_hdr(skb); if (ipv4_is_multicast(iph->daddr) && (!mc->enable_retag || (mc->enable_retag && (ipv4_get_dsfield(iph) == dscp)))) { ip_eth_mc_map(iph->daddr, eh->h_dest); if (mc->debug && printk_ratelimit()) { MC_PRINT("Decap the group "MC_IP4_STR" back to "MC_MAC_STR"\n", MC_IP4_FMT((u8 *)(&iph->daddr)) ,MC_MAC_FMT(eh->h_dest)); } skb->pkt_type = PACKET_MULTICAST; } } break; #ifdef HYBRID_MC_MLD case ETH_P_IPV6: { struct ipv6hdr *iph6 = ipv6_hdr(skb); if (ipv6_addr_is_multicast(&iph6->daddr) && (!mc->enable_retag || (mc->enable_retag && (ipv6_get_dsfield(iph6) == dscp)))) { ipv6_eth_mc_map(&iph6->daddr, eh->h_dest); if (mc->debug && printk_ratelimit()) { MC_PRINT("Decap the group "MC_IP6_STR" back to "MC_MAC_STR"\n", MC_IP6_FMT((__be16 *)(&iph6->daddr)) ,MC_MAC_FMT(eh->h_dest)); } skb->pkt_type = PACKET_MULTICAST; } } break; #endif } out: return NF_ACCEPT; }
static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph, int len, struct net_lro_desc *lro_desc) { /* check ip header: don't aggregate padded frames */ if (ntohs(iph->tot_len) != len) return -1; if (TCP_PAYLOAD_LENGTH(iph, tcph) == 0) return -1; if (iph->ihl != IPH_LEN_WO_OPTIONS) return -1; if (tcph->cwr || tcph->ece || tcph->urg || !tcph->ack || tcph->rst || tcph->syn || tcph->fin) return -1; if (INET_ECN_is_ce(ipv4_get_dsfield(iph))) return -1; if (tcph->doff != TCPH_LEN_WO_OPTIONS && tcph->doff != TCPH_LEN_W_TIMESTAMP) return -1; /* check tcp options (only timestamp allowed) */ if (tcph->doff == TCPH_LEN_W_TIMESTAMP) { __be32 *topt = (__be32 *)(tcph + 1); if (*topt != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) return -1; /* timestamp should be in right order */ topt++; if (lro_desc && after(ntohl(lro_desc->tcp_rcv_tsval), ntohl(*topt))) return -1; /* timestamp reply should not be zero */ topt++; if (*topt == 0) return -1; } return 0; }
static inline int ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); struct iphdr *iph = ip_hdr(skb); int encap_limit = -1; struct flowi fl; __u8 dsfield; __u32 mtu; int err; if ((t->parms.proto != IPPROTO_IPIP && t->parms.proto != 0) || !ip6_tnl_xmit_ctl(t)) return -1; if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) encap_limit = t->parms.encap_limit; memcpy(&fl, &t->fl, sizeof (fl)); fl.proto = IPPROTO_IPIP; dsfield = ipv4_get_dsfield(iph); if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) fl.fl6_flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT) & IPV6_TCLASS_MASK; err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); if (err != 0) { /* XXX: send ICMP error even if DF is not set. */ if (err == -EMSGSIZE) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); return -1; } return 0; }