/* C++ would be better for this. Please don't torture me with this code * ever again. */ static inline unsigned int csum_and_copy_to_dst(struct kvec_dst *dst, const char *from, int len, unsigned int csum) { do { int cnt = len; if (dst->space < cnt) cnt = dst->space; memcpy(dst->dst, from, cnt); csum = csum_partial_copy_nocheck(from, dst->dst, cnt, csum); from += cnt; dst->space -= cnt; dst->dst += cnt; len -= cnt; if (!dst->space && len) { kvec_dst_unmap(dst); dst->let++; dst->offset = 0; kvec_dst_map(dst); if (!dst->space) BUG(); } } while (len); return csum; }
static int rt_icmp_glue_reply_bits(const void *p, char *to, unsigned int offset, unsigned int fraglen) { struct icmp_bxm *icmp_param = (struct icmp_bxm *)p; struct icmphdr *icmph; unsigned long csum; /* TODO: add support for fragmented ICMP packets */ if (offset != 0) return -EMSGSIZE; csum = csum_partial_copy_nocheck((void *)&icmp_param->head, to, icmp_param->head_len, icmp_param->csum); csum = rtskb_copy_and_csum_bits(icmp_param->data.skb, icmp_param->offset, to + icmp_param->head_len, fraglen - icmp_param->head_len, csum); icmph = (struct icmphdr *)to; icmph->checksum = csum_fold(csum); return 0; }
/*** * rtskb_copy_and_csum_bits */ unsigned int rtskb_copy_and_csum_bits(const struct rtskb *skb, int offset, u8 *to, int len, unsigned int csum) { int copy; /* Copy header. */ if ((copy = skb->len-offset) > 0) { if (copy > len) copy = len; csum = csum_partial_copy_nocheck(skb->data+offset, to, copy, csum); if ((len -= copy) == 0) return csum; offset += copy; to += copy; } RTNET_ASSERT(len == 0, ); return csum; }
/*** * rtskb_copy_and_csum_bits */ unsigned int rtskb_copy_and_csum_bits(const struct rtskb *skb, int offset, u8 *to, int len, unsigned int csum) { int copy; int start = skb->len - skb->data_len; int pos = 0; /* Copy header. */ if ((copy = start-offset) > 0) { if (copy > len) copy = len; csum = csum_partial_copy_nocheck(skb->data+offset, to, copy, csum); if ((len -= copy) == 0) return csum; offset += copy; to += copy; pos = copy; } BUG(); return csum; }
static int rt_icmp_glue_reply_bits(const void *p, char *to, unsigned int offset, unsigned int fraglen) { struct icmp_bxm *icmp_param = (struct icmp_bxm *)p; struct icmphdr *icmph; unsigned long csum; RTNET_ASSERT(offset == 0, rtos_print("RTnet: %s() does not support fragmentation.", __FUNCTION__); return -1;); csum = csum_partial_copy_nocheck((void *)&icmp_param->head, to, icmp_param->head_len, icmp_param->csum); csum = rtskb_copy_and_csum_bits(icmp_param->data.skb, icmp_param->offset, to + icmp_param->head_len, fraglen - icmp_param->head_len, csum); icmph = (struct icmphdr *)to; icmph->checksum = csum_fold(csum); return 0; }