static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc) { struct iphdr *iph = lro_desc->iph; struct tcphdr *tcph = lro_desc->tcph; __be32 *p; __wsum tcp_hdr_csum; tcph->ack_seq = lro_desc->tcp_ack; tcph->window = lro_desc->tcp_window; if (lro_desc->tcp_saw_tstamp) { p = (__be32 *)(tcph + 1); *(p+2) = lro_desc->tcp_rcv_tsecr; } csum_replace2(&iph->check, iph->tot_len, htons(lro_desc->ip_tot_len)); iph->tot_len = htons(lro_desc->ip_tot_len); tcph->check = 0; tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), 0); lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum); tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, lro_desc->ip_tot_len - IP_HDR_LEN(iph), IPPROTO_TCP, lro_desc->data_csum); }
static void udpencap_fix4(struct sk_buff *skb, const struct xt_udpencap_tginfo *info) { struct iphdr *iph = ip_hdr(skb); bool fix_csum = (skb->ip_summed == CHECKSUM_COMPLETE && !info->encap); __be16 newlen = htons(ntohs(iph->tot_len) + (info->encap ? 1 : -1) * sizeof(struct udphdr)); if (fix_csum) { skb->csum = csum_sub(skb->csum, csum_partial(&iph->tot_len, 2, 0)); skb->csum = csum_sub(skb->csum, csum_partial(&iph->protocol, 3, 0)); } csum_replace2(&iph->check, iph->tot_len, newlen); iph->tot_len = newlen; if (iph->protocol != info->proto) { csum_replace2(&iph->check, htons(iph->protocol), htons(info->proto)); iph->protocol = info->proto; } if (fix_csum) { skb->csum = csum_add(skb->csum, csum_partial(&iph->tot_len, 2, 0)); skb->csum = csum_add(skb->csum, csum_partial(&iph->protocol, 3, 0)); } }
static bool mpls_egress(struct mpls_route *rt, struct sk_buff *skb, struct mpls_entry_decoded dec) { /* RFC4385 and RFC5586 encode other packets in mpls such that * they don't conflict with the ip version number, making * decoding by examining the ip version correct in everything * except for the strangest cases. * * The strange cases if we choose to support them will require * manual configuration. */ struct iphdr *hdr4; bool success = true; /* The IPv4 code below accesses through the IPv4 header * checksum, which is 12 bytes into the packet. * The IPv6 code below accesses through the IPv6 hop limit * which is 8 bytes into the packet. * * For all supported cases there should always be at least 12 * bytes of packet data present. The IPv4 header is 20 bytes * without options and the IPv6 header is always 40 bytes * long. */ if (!pskb_may_pull(skb, 12)) return false; /* Use ip_hdr to find the ip protocol version */ hdr4 = ip_hdr(skb); if (hdr4->version == 4) { skb->protocol = htons(ETH_P_IP); csum_replace2(&hdr4->check, htons(hdr4->ttl << 8), htons(dec.ttl << 8)); hdr4->ttl = dec.ttl; } else if (hdr4->version == 6) { struct ipv6hdr *hdr6 = ipv6_hdr(skb); skb->protocol = htons(ETH_P_IPV6); hdr6->hop_limit = dec.ttl; } else /* version 0 and version 1 are used by pseudo wires */ success = false; return success; }
/* set ECT codepoint from IP header. * return false if there was an error. */ static inline bool set_ect_ip(struct sk_buff *skb, const struct ipt_ECN_info *einfo) { struct iphdr *iph = ip_hdr(skb); if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { __u8 oldtos; if (!skb_make_writable(skb, sizeof(struct iphdr))) return false; iph = ip_hdr(skb); oldtos = iph->tos; iph->tos &= ~IPT_ECN_IP_MASK; iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK); csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); } return true; }
static void cvsw_apply_set_nw_tos(struct sk_buff *skb, const __u8 tos) { __u8 *nw; nw = skb_util_get_network_header(skb); if (unlikely(! nw)) { return ; } if (((struct iphdr*)nw)->version == 4) { off_t off; struct iphdr *ip4; ip4 = (struct iphdr*)nw; off = offsetof(struct iphdr, tos); /* Update L3 checksum */ csum_replace2(&ip4->check, htons(*((__u16*)&ip4->tos)), tos << 8 | nw[off + 1]); /* Set ToS */ ip4->tos = tos; } else if (((struct ipv6hdr*)nw)->version == 6) {
static unsigned int ttl_tg(struct sk_buff *skb, const struct xt_action_param *par) { struct iphdr *iph; const struct ipt_TTL_info *info = par->targinfo; int new_ttl; if (!skb_make_writable(skb, skb->len)) return NF_DROP; iph = ip_hdr(skb); switch (info->mode) { case IPT_TTL_SET: new_ttl = info->ttl; break; case IPT_TTL_INC: new_ttl = iph->ttl + info->ttl; if (new_ttl > 255) new_ttl = 255; break; case IPT_TTL_DEC: new_ttl = iph->ttl - info->ttl; if (new_ttl < 0) new_ttl = 0; break; default: new_ttl = iph->ttl; break; } if (new_ttl != iph->ttl) { csum_replace2(&iph->check, htons(iph->ttl << 8), htons(new_ttl << 8)); iph->ttl = new_ttl; } return XT_CONTINUE; }
static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl) { csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8)); nh->ttl = new_ttl; }