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