+ /* Insert the checksum in the existing chain */
+ if (offset + ip_offset + sizeof(u_short) > m->m_len) {
+ char tmp[2];
+
+#if DEBUG
+ printf("delayed m_copyback, m->len: %ld off: %d p: %d\n",
+ m->m_len, offset + ip_offset, ip->ip_p);
+#endif
+ *(u_short *)tmp = csum;
+ m_copyback(m, offset + ip_offset, 2, tmp);
+ } else
+ *(u_short *)(m->m_data + offset + ip_offset) = csum;
+}
+
+void
+in_delayed_cksum(struct mbuf *m)
+{
+ in_delayed_cksum_offset(m, 0);
+}
+
+void
+in_cksum_offset(struct mbuf* m, size_t ip_offset)
+{
+ struct ip* ip = NULL;
+ int hlen = 0;
+ unsigned char buf[sizeof(struct ip)];
+ int swapped = 0;
+
+ while (ip_offset >= m->m_len) {
+ ip_offset -= m->m_len;
+ m = m->m_next;
+ if (m == NULL) {
+ printf("in_cksum_offset failed - ip_offset wasn't in the packet\n");
+ return;
+ }
+ }
+
+ /* Sometimes the IP header is not contiguous, yes this can happen! */
+ if (ip_offset + sizeof(struct ip) > m->m_len) {
+
+#if DEBUG
+ printf("in_cksum_offset - delayed m_pullup, m->len: %ld off: %lu\n",
+ m->m_len, ip_offset);
+#endif
+ m_copydata(m, ip_offset, sizeof(struct ip), (caddr_t) buf);
+
+ ip = (struct ip *)buf;
+ ip->ip_sum = 0;
+ m_copyback(m, ip_offset + offsetof(struct ip, ip_sum), 2, (caddr_t)&ip->ip_sum);
+ } else {
+ ip = (struct ip*)(m->m_data + ip_offset);
+ ip->ip_sum = 0;
+ }
+
+ /* Gross */
+ if (ip_offset) {
+ m->m_len -= ip_offset;
+ m->m_data += ip_offset;
+ }
+
+#ifdef _IP_VHL
+ hlen = IP_VHL_HL(ip->ip_vhl) << 2;
+#else
+ hlen = ip->ip_hl << 2;
+#endif
+ /*
+ * We could be in the context of an IP or interface filter; in the
+ * former case, ip_len would be in host order while for the latter
+ * it would be in network (correct) order. Because of this, we
+ * attempt to interpret the length field by comparing it against
+ * the actual packet length. If the comparison fails, byte swap
+ * the length and check again. If it still fails, then the packet
+ * is bogus and we give up.
+ */
+ if (ntohs(ip->ip_len) != (m->m_pkthdr.len - ip_offset)) {
+ ip->ip_len = SWAP16(ip->ip_len);
+ swapped = 1;
+ if (ntohs(ip->ip_len) != (m->m_pkthdr.len - ip_offset)) {
+ ip->ip_len = SWAP16(ip->ip_len);
+ printf("in_cksum_offset: ip_len %d (%d) "
+ "doesn't match actual length %lu\n",
+ ip->ip_len, SWAP16(ip->ip_len),
+ (m->m_pkthdr.len - ip_offset));
+ return;
+ }
+ }
+
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m, hlen);
+ if (swapped)
+ ip->ip_len = SWAP16(ip->ip_len);
+
+ /* Gross */
+ if (ip_offset) {
+ if (M_LEADINGSPACE(m) < ip_offset)
+ panic("in_cksum_offset - chain modified!\n");
+ m->m_len += ip_offset;
+ m->m_data -= ip_offset;
+ }
+
+ /* Insert the checksum in the existing chain if IP header not contiguous */
+ if (ip_offset + sizeof(struct ip) > m->m_len) {
+ char tmp[2];
+
+#if DEBUG
+ printf("in_cksum_offset m_copyback, m->len: %lu off: %lu p: %d\n",
+ m->m_len, ip_offset + offsetof(struct ip, ip_sum), ip->ip_p);
+#endif
+ *(u_short *)tmp = ip->ip_sum;
+ m_copyback(m, ip_offset + offsetof(struct ip, ip_sum), 2, tmp);