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
ip_csum(mp,offset,sum)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