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