1 /* $NetBSD: cpu_in_cksum.c,v 1.2 2025/01/05 22:11:17 andvar Exp $ */ 2 /*- 3 * Copyright (c) 2008 Joerg Sonnenberger <joerg (at) NetBSD.org>. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: cpu_in_cksum.c,v 1.2 2025/01/05 22:11:17 andvar Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/mbuf.h> 36 #include <sys/systm.h> 37 38 #include <netinet/in.h> 39 40 /* 41 * Taken from sys/netinet/cpu_in_cksum.c and modified to use old MD oc_cksum(). 42 */ 43 44 /* in <m68k/m68k/oc_cksum.s> */ 45 extern int oc_cksum(uint8_t *, int, uint32_t); 46 47 int 48 cpu_in_cksum(struct mbuf *m, int len, int off, uint32_t initial_sum) 49 { 50 int mlen; 51 uint32_t sum, partial; 52 unsigned int final_acc; 53 uint8_t *data; 54 bool needs_swap, started_on_odd; 55 56 KASSERT(len >= 0); 57 KASSERT(off >= 0); 58 59 needs_swap = false; 60 started_on_odd = false; 61 sum = (initial_sum >> 16) + (initial_sum & 0xffff); 62 63 for (;;) { 64 if (__predict_false(m == NULL)) { 65 printf("in_cksum: out of data\n"); 66 return -1; 67 } 68 mlen = m->m_len; 69 if (mlen > off) { 70 mlen -= off; 71 data = mtod(m, uint8_t *) + off; 72 goto post_initial_offset; 73 } 74 off -= mlen; 75 if (len == 0) 76 break; 77 m = m->m_next; 78 } 79 80 for (; len > 0; m = m->m_next) { 81 if (__predict_false(m == NULL)) { 82 printf("in_cksum: out of data\n"); 83 return -1; 84 } 85 mlen = m->m_len; 86 data = mtod(m, uint8_t *); 87 post_initial_offset: 88 if (mlen == 0) 89 continue; 90 if (mlen > len) 91 mlen = len; 92 len -= mlen; 93 94 partial = 0; 95 if ((uintptr_t)data & 1) { 96 /* Align on word boundary */ 97 started_on_odd = !started_on_odd; 98 /* We are big endian */ 99 partial = *data; 100 ++data; 101 --mlen; 102 } 103 needs_swap = started_on_odd; 104 105 /* A possible trailing odd byte is handled in oc_cksum() */ 106 if (mlen & 1) 107 started_on_odd = !started_on_odd; 108 /* 16 bit word alignment is enough on m68k */ 109 partial = oc_cksum(data, mlen, partial); 110 111 if (needs_swap) 112 partial = (partial << 8) + (partial >> 24); 113 sum += (partial >> 16) + (partial & 0xffff); 114 /* 115 * Reduce sum to allow potential byte swap 116 * in the next iteration without carry. 117 */ 118 sum = (sum >> 16) + (sum & 0xffff); 119 } 120 final_acc = ((sum >> 16) & 0xffff) + (sum & 0xffff); 121 final_acc = (final_acc >> 16) + (final_acc & 0xffff); 122 return ~final_acc & 0xffff; 123 } 124