1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1992,1997 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 /* Copyright (c) 1990 Mentat Inc. */ 27 28 #include <sys/types.h> 29 #include <sys/stream.h> 30 #include <sys/ddi.h> 31 #include <sys/isa_defs.h> 32 #include <inet/common.h> 33 34 #define FOLD_SUM(sum) \ 35 { sum = (sum >> 16) + (sum & 0xFFFF); sum = (sum >> 16) + (sum & 0xFFFF); } 36 #define U16AM(p, i, m) ((((uint16_t *)(p))[i]) & (uint32_t)(m)) 37 38 /* 39 * For maximum efficiency, these access macros should be redone for 40 * machines that can access unaligned data. NOTE: these assume 41 * ability to fetch from a zero extended 'uint8_t' and 'uint16_t'. Add explicit 42 * masks in the U8_FETCH, U16_FETCH, PREV_TWO and NEXT_TWO as needed. 43 */ 44 45 #ifdef _LITTLE_ENDIAN 46 #define U8_FETCH_FIRST(p) ((p)[0]) 47 #define U8_FETCH_SECOND(p) (((uint32_t)(p)[0]) << 8) 48 #define PREV_ONE(p) U16AM(p, -1, 0xFF00) 49 #define NEXT_ONE(p) U16AM(p, 0, 0xFF) 50 #else 51 #define U8_FETCH_FIRST(p) ((uint32_t)((p)[0]) << 8) 52 #define U8_FETCH_SECOND(p) ((p)[0]) 53 #define PREV_ONE(p) U16AM(p, -1, 0xFF) 54 #define NEXT_ONE(p) U16AM(p, 0, 0xFF00) 55 #endif 56 57 #define U16_FETCH(p) U8_FETCH_FIRST(p) + U8_FETCH_SECOND(p+1) 58 #define PREV_TWO(p) ((uint32_t)(((uint16_t *)(p))[-1])) 59 #define NEXT_TWO(p) ((uint32_t)(((uint16_t *)(p))[0])) 60 61 /* 62 * Return the ones complement checksum from the mblk chain at mp, 63 * after skipping offset bytes, and adding in the supplied partial 64 * sum. Note that a final complement of the return value is needed 65 * if no further contributions to the checksum are forthcoming. 66 */ 67 uint16_t 68 ip_csum(mp, offset, sum) 69 mblk_t *mp; 70 int offset; 71 uint32_t sum; 72 { 73 uint8_t *startp = mp->b_rptr + offset; 74 uint8_t *endp = mp->b_wptr; 75 /* >= 0x2 means flipped for memory align, 0x1 means last count was odd */ 76 int odd_total = 0; 77 78 #ifdef TEST_COVERAGE 79 mblk_t *safe_mp; 80 #define INIT_COVERAGE() (safe_mp = mp, safe_mp->b_next = NULL) 81 #define MARK_COVERAGE(flag) (safe_mp->b_next = \ 82 (mblk_t *)((uint32_t)safe_mp->b_next | flag)) 83 #else 84 #define INIT_COVERAGE() /* */ 85 #define MARK_COVERAGE(flag) /* */ 86 #endif 87 88 for (;;) { 89 INIT_COVERAGE(); 90 if ((endp - startp) < 10) { 91 MARK_COVERAGE(0x1); 92 while ((endp - startp) >= 2) { 93 MARK_COVERAGE(0x2); 94 sum += U16_FETCH(startp); 95 startp += 2; 96 } 97 if ((endp - startp) >= 1) { 98 MARK_COVERAGE(0x4); 99 odd_total = 1; 100 sum += U8_FETCH_FIRST(startp); 101 } 102 MARK_COVERAGE(0x8); 103 FOLD_SUM(sum); 104 goto next_frag; 105 } 106 if ((uint32_t)startp & 0x1) { 107 MARK_COVERAGE(0x10); 108 odd_total = 3; 109 startp++; 110 sum = (sum << 8) + PREV_ONE(startp); 111 } 112 if ((uint32_t)startp & 0x2) { 113 MARK_COVERAGE(0x20); 114 startp += 2; 115 sum += PREV_TWO(startp); 116 } 117 if ((uint32_t)endp & 0x1) { 118 MARK_COVERAGE(0x40); 119 odd_total ^= 0x1; 120 endp--; 121 sum += NEXT_ONE(endp); 122 } 123 if ((uint32_t)endp & 0x2) { 124 MARK_COVERAGE(0x80); 125 endp -= 2; 126 sum += NEXT_TWO(endp); 127 } 128 129 { 130 #ifdef NOT_ALL_PTRS_EQUAL 131 #define INC_PTR(cnt) ptr += cnt 132 #define INC_ENDPTR(cnt) endptr += cnt 133 uint32_t *ptr = (uint32_t *)startp; 134 uint32_t *endptr = (uint32_t *)endp; 135 #else 136 #define INC_PTR(cnt) startp += (cnt * sizeof (uint32_t)) 137 #define INC_ENDPTR(cnt) endp += (cnt * sizeof (uint32_t)) 138 #define ptr ((uint32_t *)startp) 139 #define endptr ((uint32_t *)endp) 140 #endif 141 142 143 #ifdef USE_FETCH_AND_SHIFT 144 uint32_t u1, u2; 145 uint32_t mask = 0xFFFF; 146 #define LOAD1(i) u1 = ptr[i] 147 #define LOAD2(i) u2 = ptr[i] 148 #define SUM1(i) sum += (u1 & mask) + (u1 >> 16) 149 #define SUM2(i) sum += (u2 & mask) + (u2 >> 16) 150 #endif 151 152 #ifdef USE_FETCH_AND_ADDC 153 uint32_t u1, u2; 154 #define LOAD1(i) u1 = ptr[i] 155 #define LOAD2(i) u2 = ptr[i] 156 #define SUM1(i) sum += u1 157 #define SUM2(i) sum += u2 158 #endif 159 160 #ifdef USE_ADDC 161 #define SUM1(i) sum += ptr[i] 162 #endif 163 164 #ifdef USE_POSTINC 165 #define SUM1(i) sum += *((uint16_t *)ptr)++; sum += *((uint16_t *)ptr)++ 166 #undef INC_PTR 167 #define INC_PTR(i) /* */ 168 #endif 169 170 #ifndef LOAD1 171 #define LOAD1(i) /* */ 172 #endif 173 174 #ifndef LOAD2 175 #define LOAD2(i) /* */ 176 #endif 177 178 #ifndef SUM2 179 #define SUM2(i) SUM1(i) 180 #endif 181 182 /* USE_INDEXING is the default */ 183 #ifndef SUM1 184 #define SUM1(i) 185 sum += ((uint16_t *)ptr)[i * 2]; sum += ((uint16_t *)ptr)[(i * 2) + 1] 186 #endif 187 188 LOAD1(0); 189 INC_ENDPTR(-8); 190 if (ptr <= endptr) { 191 MARK_COVERAGE(0x100); 192 do { 193 LOAD2(1); SUM1(0); 194 LOAD1(2); SUM2(1); 195 LOAD2(3); SUM1(2); 196 LOAD1(4); SUM2(3); 197 LOAD2(5); SUM1(4); 198 LOAD1(6); SUM2(5); 199 LOAD2(7); SUM1(6); 200 LOAD1(8); SUM2(7); 201 INC_PTR(8); 202 } while (ptr <= endptr); 203 } 204 #ifdef USE_TAIL_SWITCH 205 switch ((endptr + 8) - ptr) { 206 case 7: LOAD2(6); SUM2(6); 207 case 6: LOAD2(5); SUM2(5); 208 case 5: LOAD2(4); SUM2(4); 209 case 4: LOAD2(3); SUM2(3); 210 case 3: LOAD2(2); SUM2(2); 211 case 2: LOAD2(1); SUM2(1); 212 case 1: SUM1(0); 213 case 0: break; 214 } 215 #else 216 INC_ENDPTR(4); 217 if (ptr <= endptr) { 218 MARK_COVERAGE(0x200); 219 LOAD2(1); SUM1(0); 220 LOAD1(2); SUM2(1); 221 LOAD2(3); SUM1(2); 222 LOAD1(4); SUM2(3); 223 INC_PTR(4); 224 } 225 INC_ENDPTR(4); 226 if (ptr < endptr) { 227 MARK_COVERAGE(0x400); 228 do { 229 SUM1(0); LOAD1(1); 230 INC_PTR(1); 231 } while (ptr < endptr); 232 } 233 #endif 234 } 235 236 FOLD_SUM(sum); 237 if (odd_total > 1) { 238 MARK_COVERAGE(0x800); 239 sum = ((sum << 8) | (sum >> 8)) & 0xFFFF; 240 odd_total -= 2; 241 } 242 next_frag: 243 mp = mp->b_cont; 244 if (!mp) { 245 MARK_COVERAGE(0x1000); 246 { 247 uint32_t u1 = sum; 248 return ((uint16_t)u1); 249 } 250 } 251 MARK_COVERAGE(0x4000); 252 startp = mp->b_rptr; 253 endp = mp->b_wptr; 254 if (odd_total && (endp > startp)) { 255 MARK_COVERAGE(0x8000); 256 odd_total = 0; 257 sum += U8_FETCH_SECOND(startp); 258 startp++; 259 } 260 } 261 } 262 #undef endptr 263 #undef INIT_COVERAGE 264 #undef INC_PTR 265 #undef INC_ENDPTR 266 #undef LOAD1 267 #undef LOAD2 268 #undef MARK_COVERAGE 269 #undef ptr 270 #undef SUM1 271 #undef SUM2 272 273 274 275 #undef FOLD_SUM 276 #undef NEXT_ONE 277 #undef NEXT_TWO 278 #undef PREV_ONE 279 #undef PREV_TWO 280 #undef U8_FETCH_FIRST 281 #undef U8_FETCH_SECOND 282 #undef U16AM 283 #undef U16_FETCH 284