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