1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3 *
4 * Copyright (c) 2004 Topspin Corporation. All rights reserved.
5 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
6 *
7 * This software is available to you under a choice of one of two
8 * licenses. You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
12 *
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
15 * conditions are met:
16 *
17 * - Redistributions of source code must retain the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer.
20 *
21 * - Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials
24 * provided with the distribution.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <linux/errno.h>
40 #include <linux/string.h>
41 #include <linux/if_ether.h>
42
43 #include <rdma/ib_pack.h>
44
45 #include <machine/in_cksum.h>
46
47 #define STRUCT_FIELD(header, field) \
48 .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \
49 .struct_size_bytes = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \
50 .field_name = #header ":" #field
51
52 static const struct ib_field lrh_table[] = {
53 { STRUCT_FIELD(lrh, virtual_lane),
54 .offset_words = 0,
55 .offset_bits = 0,
56 .size_bits = 4 },
57 { STRUCT_FIELD(lrh, link_version),
58 .offset_words = 0,
59 .offset_bits = 4,
60 .size_bits = 4 },
61 { STRUCT_FIELD(lrh, service_level),
62 .offset_words = 0,
63 .offset_bits = 8,
64 .size_bits = 4 },
65 { RESERVED,
66 .offset_words = 0,
67 .offset_bits = 12,
68 .size_bits = 2 },
69 { STRUCT_FIELD(lrh, link_next_header),
70 .offset_words = 0,
71 .offset_bits = 14,
72 .size_bits = 2 },
73 { STRUCT_FIELD(lrh, destination_lid),
74 .offset_words = 0,
75 .offset_bits = 16,
76 .size_bits = 16 },
77 { RESERVED,
78 .offset_words = 1,
79 .offset_bits = 0,
80 .size_bits = 5 },
81 { STRUCT_FIELD(lrh, packet_length),
82 .offset_words = 1,
83 .offset_bits = 5,
84 .size_bits = 11 },
85 { STRUCT_FIELD(lrh, source_lid),
86 .offset_words = 1,
87 .offset_bits = 16,
88 .size_bits = 16 }
89 };
90
91 static const struct ib_field eth_table[] = {
92 { STRUCT_FIELD(eth, dmac_h),
93 .offset_words = 0,
94 .offset_bits = 0,
95 .size_bits = 32 },
96 { STRUCT_FIELD(eth, dmac_l),
97 .offset_words = 1,
98 .offset_bits = 0,
99 .size_bits = 16 },
100 { STRUCT_FIELD(eth, smac_h),
101 .offset_words = 1,
102 .offset_bits = 16,
103 .size_bits = 16 },
104 { STRUCT_FIELD(eth, smac_l),
105 .offset_words = 2,
106 .offset_bits = 0,
107 .size_bits = 32 },
108 { STRUCT_FIELD(eth, type),
109 .offset_words = 3,
110 .offset_bits = 0,
111 .size_bits = 16 }
112 };
113
114 static const struct ib_field vlan_table[] = {
115 { STRUCT_FIELD(vlan, tag),
116 .offset_words = 0,
117 .offset_bits = 0,
118 .size_bits = 16 },
119 { STRUCT_FIELD(vlan, type),
120 .offset_words = 0,
121 .offset_bits = 16,
122 .size_bits = 16 }
123 };
124
125 static const struct ib_field ip4_table[] = {
126 { STRUCT_FIELD(ip4, ver),
127 .offset_words = 0,
128 .offset_bits = 0,
129 .size_bits = 4 },
130 { STRUCT_FIELD(ip4, hdr_len),
131 .offset_words = 0,
132 .offset_bits = 4,
133 .size_bits = 4 },
134 { STRUCT_FIELD(ip4, tos),
135 .offset_words = 0,
136 .offset_bits = 8,
137 .size_bits = 8 },
138 { STRUCT_FIELD(ip4, tot_len),
139 .offset_words = 0,
140 .offset_bits = 16,
141 .size_bits = 16 },
142 { STRUCT_FIELD(ip4, id),
143 .offset_words = 1,
144 .offset_bits = 0,
145 .size_bits = 16 },
146 { STRUCT_FIELD(ip4, frag_off),
147 .offset_words = 1,
148 .offset_bits = 16,
149 .size_bits = 16 },
150 { STRUCT_FIELD(ip4, ttl),
151 .offset_words = 2,
152 .offset_bits = 0,
153 .size_bits = 8 },
154 { STRUCT_FIELD(ip4, protocol),
155 .offset_words = 2,
156 .offset_bits = 8,
157 .size_bits = 8 },
158 { STRUCT_FIELD(ip4, check),
159 .offset_words = 2,
160 .offset_bits = 16,
161 .size_bits = 16 },
162 { STRUCT_FIELD(ip4, saddr),
163 .offset_words = 3,
164 .offset_bits = 0,
165 .size_bits = 32 },
166 { STRUCT_FIELD(ip4, daddr),
167 .offset_words = 4,
168 .offset_bits = 0,
169 .size_bits = 32 }
170 };
171
172 static const struct ib_field udp_table[] = {
173 { STRUCT_FIELD(udp, sport),
174 .offset_words = 0,
175 .offset_bits = 0,
176 .size_bits = 16 },
177 { STRUCT_FIELD(udp, dport),
178 .offset_words = 0,
179 .offset_bits = 16,
180 .size_bits = 16 },
181 { STRUCT_FIELD(udp, length),
182 .offset_words = 1,
183 .offset_bits = 0,
184 .size_bits = 16 },
185 { STRUCT_FIELD(udp, csum),
186 .offset_words = 1,
187 .offset_bits = 16,
188 .size_bits = 16 }
189 };
190
191 static const struct ib_field grh_table[] = {
192 { STRUCT_FIELD(grh, ip_version),
193 .offset_words = 0,
194 .offset_bits = 0,
195 .size_bits = 4 },
196 { STRUCT_FIELD(grh, traffic_class),
197 .offset_words = 0,
198 .offset_bits = 4,
199 .size_bits = 8 },
200 { STRUCT_FIELD(grh, flow_label),
201 .offset_words = 0,
202 .offset_bits = 12,
203 .size_bits = 20 },
204 { STRUCT_FIELD(grh, payload_length),
205 .offset_words = 1,
206 .offset_bits = 0,
207 .size_bits = 16 },
208 { STRUCT_FIELD(grh, next_header),
209 .offset_words = 1,
210 .offset_bits = 16,
211 .size_bits = 8 },
212 { STRUCT_FIELD(grh, hop_limit),
213 .offset_words = 1,
214 .offset_bits = 24,
215 .size_bits = 8 },
216 { STRUCT_FIELD(grh, source_gid),
217 .offset_words = 2,
218 .offset_bits = 0,
219 .size_bits = 128 },
220 { STRUCT_FIELD(grh, destination_gid),
221 .offset_words = 6,
222 .offset_bits = 0,
223 .size_bits = 128 }
224 };
225
226 static const struct ib_field bth_table[] = {
227 { STRUCT_FIELD(bth, opcode),
228 .offset_words = 0,
229 .offset_bits = 0,
230 .size_bits = 8 },
231 { STRUCT_FIELD(bth, solicited_event),
232 .offset_words = 0,
233 .offset_bits = 8,
234 .size_bits = 1 },
235 { STRUCT_FIELD(bth, mig_req),
236 .offset_words = 0,
237 .offset_bits = 9,
238 .size_bits = 1 },
239 { STRUCT_FIELD(bth, pad_count),
240 .offset_words = 0,
241 .offset_bits = 10,
242 .size_bits = 2 },
243 { STRUCT_FIELD(bth, transport_header_version),
244 .offset_words = 0,
245 .offset_bits = 12,
246 .size_bits = 4 },
247 { STRUCT_FIELD(bth, pkey),
248 .offset_words = 0,
249 .offset_bits = 16,
250 .size_bits = 16 },
251 { RESERVED,
252 .offset_words = 1,
253 .offset_bits = 0,
254 .size_bits = 8 },
255 { STRUCT_FIELD(bth, destination_qpn),
256 .offset_words = 1,
257 .offset_bits = 8,
258 .size_bits = 24 },
259 { STRUCT_FIELD(bth, ack_req),
260 .offset_words = 2,
261 .offset_bits = 0,
262 .size_bits = 1 },
263 { RESERVED,
264 .offset_words = 2,
265 .offset_bits = 1,
266 .size_bits = 7 },
267 { STRUCT_FIELD(bth, psn),
268 .offset_words = 2,
269 .offset_bits = 8,
270 .size_bits = 24 }
271 };
272
273 static const struct ib_field deth_table[] = {
274 { STRUCT_FIELD(deth, qkey),
275 .offset_words = 0,
276 .offset_bits = 0,
277 .size_bits = 32 },
278 { RESERVED,
279 .offset_words = 1,
280 .offset_bits = 0,
281 .size_bits = 8 },
282 { STRUCT_FIELD(deth, source_qpn),
283 .offset_words = 1,
284 .offset_bits = 8,
285 .size_bits = 24 }
286 };
287
288 __sum16 ib_ud_ip4_csum(struct ib_ud_header *header)
289 {
290 #if defined(INET) || defined(INET6)
291 struct ip iph;
292
293 iph.ip_hl = 5;
294 iph.ip_v = 4;
295 iph.ip_tos = header->ip4.tos;
296 iph.ip_len = header->ip4.tot_len;
297 iph.ip_id = header->ip4.id;
298 iph.ip_off = header->ip4.frag_off;
299 iph.ip_ttl = header->ip4.ttl;
300 iph.ip_p = header->ip4.protocol;
301 iph.ip_sum = 0;
302 iph.ip_src.s_addr = header->ip4.saddr;
303 iph.ip_dst.s_addr = header->ip4.daddr;
304
305 return in_cksum_hdr(&iph);
306 #else
307 return 0;
308 #endif
309 }
310 EXPORT_SYMBOL(ib_ud_ip4_csum);
311
312 /**
313 * ib_ud_header_init - Initialize UD header structure
314 * @payload_bytes:Length of packet payload
315 * @lrh_present: specify if LRH is present
316 * @eth_present: specify if Eth header is present
317 * @vlan_present: packet is tagged vlan
318 * @grh_present: GRH flag (if non-zero, GRH will be included)
319 * @ip_version: if non-zero, IP header, V4 or V6, will be included
320 * @udp_present :if non-zero, UDP header will be included
321 * @immediate_present: specify if immediate data is present
322 * @header:Structure to initialize
323 */
324 int ib_ud_header_init(int payload_bytes,
325 int lrh_present,
326 int eth_present,
327 int vlan_present,
328 int grh_present,
329 int ip_version,
330 int udp_present,
331 int immediate_present,
332 struct ib_ud_header *header)
333 {
334 size_t udp_bytes = udp_present ? IB_UDP_BYTES : 0;
335
336 grh_present = grh_present && !ip_version;
337 memset(header, 0, sizeof *header);
338
339 /*
340 * UDP header without IP header doesn't make sense
341 */
342 if (udp_present && ip_version != 4 && ip_version != 6)
343 return -EINVAL;
344
345 if (lrh_present) {
346 u16 packet_length;
347
348 header->lrh.link_version = 0;
349 header->lrh.link_next_header =
350 grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
351 packet_length = (IB_LRH_BYTES +
352 IB_BTH_BYTES +
353 IB_DETH_BYTES +
354 (grh_present ? IB_GRH_BYTES : 0) +
355 payload_bytes +
356 4 + /* ICRC */
357 3) / 4; /* round up */
358 header->lrh.packet_length = cpu_to_be16(packet_length);
359 }
360
361 if (vlan_present)
362 header->eth.type = cpu_to_be16(ETH_P_8021Q);
363
364 if (ip_version == 6 || grh_present) {
365 header->grh.ip_version = 6;
366 header->grh.payload_length =
367 cpu_to_be16((udp_bytes +
368 IB_BTH_BYTES +
369 IB_DETH_BYTES +
370 payload_bytes +
371 4 + /* ICRC */
372 3) & ~3); /* round up */
373 header->grh.next_header = udp_present ? IPPROTO_UDP : 0x1b;
374 }
375
376 if (ip_version == 4) {
377 header->ip4.ver = 4; /* version 4 */
378 header->ip4.hdr_len = 5; /* 5 words */
379 header->ip4.tot_len =
380 cpu_to_be16(IB_IP4_BYTES +
381 udp_bytes +
382 IB_BTH_BYTES +
383 IB_DETH_BYTES +
384 payload_bytes +
385 4); /* ICRC */
386 header->ip4.protocol = IPPROTO_UDP;
387 }
388 if (udp_present && ip_version)
389 header->udp.length =
390 cpu_to_be16(IB_UDP_BYTES +
391 IB_BTH_BYTES +
392 IB_DETH_BYTES +
393 payload_bytes +
394 4); /* ICRC */
395
396 if (immediate_present)
397 header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
398 else
399 header->bth.opcode = IB_OPCODE_UD_SEND_ONLY;
400 header->bth.pad_count = (4 - payload_bytes) & 3;
401 header->bth.transport_header_version = 0;
402
403 header->lrh_present = lrh_present;
404 header->eth_present = eth_present;
405 header->vlan_present = vlan_present;
406 header->grh_present = grh_present || (ip_version == 6);
407 header->ipv4_present = ip_version == 4;
408 header->udp_present = udp_present;
409 header->immediate_present = immediate_present;
410 return 0;
411 }
412 EXPORT_SYMBOL(ib_ud_header_init);
413
414 /**
415 * ib_ud_header_pack - Pack UD header struct into wire format
416 * @header:UD header struct
417 * @buf:Buffer to pack into
418 *
419 * ib_ud_header_pack() packs the UD header structure @header into wire
420 * format in the buffer @buf.
421 */
422 int ib_ud_header_pack(struct ib_ud_header *header,
423 void *buf)
424 {
425 int len = 0;
426
427 if (header->lrh_present) {
428 ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
429 &header->lrh, (char *)buf + len);
430 len += IB_LRH_BYTES;
431 }
432 if (header->eth_present) {
433 ib_pack(eth_table, ARRAY_SIZE(eth_table),
434 &header->eth, (char *)buf + len);
435 len += IB_ETH_BYTES;
436 }
437 if (header->vlan_present) {
438 ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
439 &header->vlan, (char *)buf + len);
440 len += IB_VLAN_BYTES;
441 }
442 if (header->grh_present) {
443 ib_pack(grh_table, ARRAY_SIZE(grh_table),
444 &header->grh, (char *)buf + len);
445 len += IB_GRH_BYTES;
446 }
447 if (header->ipv4_present) {
448 ib_pack(ip4_table, ARRAY_SIZE(ip4_table),
449 &header->ip4, (char *)buf + len);
450 len += IB_IP4_BYTES;
451 }
452 if (header->udp_present) {
453 ib_pack(udp_table, ARRAY_SIZE(udp_table),
454 &header->udp, (char *)buf + len);
455 len += IB_UDP_BYTES;
456 }
457
458 ib_pack(bth_table, ARRAY_SIZE(bth_table),
459 &header->bth, (char *)buf + len);
460 len += IB_BTH_BYTES;
461
462 ib_pack(deth_table, ARRAY_SIZE(deth_table),
463 &header->deth, (char *)buf + len);
464 len += IB_DETH_BYTES;
465
466 if (header->immediate_present) {
467 memcpy((char *)buf + len, &header->immediate_data, sizeof header->immediate_data);
468 len += sizeof header->immediate_data;
469 }
470
471 return len;
472 }
473 EXPORT_SYMBOL(ib_ud_header_pack);
474
475 /**
476 * ib_ud_header_unpack - Unpack UD header struct from wire format
477 * @header:UD header struct
478 * @buf:Buffer to pack into
479 *
480 * ib_ud_header_pack() unpacks the UD header structure @header from wire
481 * format in the buffer @buf.
482 */
483 int ib_ud_header_unpack(void *buf,
484 struct ib_ud_header *header)
485 {
486 ib_unpack(lrh_table, ARRAY_SIZE(lrh_table),
487 buf, &header->lrh);
488 buf = (char *)buf + IB_LRH_BYTES;
489
490 if (header->lrh.link_version != 0) {
491 pr_warn("Invalid LRH.link_version %d\n",
492 header->lrh.link_version);
493 return -EINVAL;
494 }
495
496 switch (header->lrh.link_next_header) {
497 case IB_LNH_IBA_LOCAL:
498 header->grh_present = 0;
499 break;
500
501 case IB_LNH_IBA_GLOBAL:
502 header->grh_present = 1;
503 ib_unpack(grh_table, ARRAY_SIZE(grh_table),
504 buf, &header->grh);
505 buf = (char *)buf + IB_GRH_BYTES;
506
507 if (header->grh.ip_version != 6) {
508 pr_warn("Invalid GRH.ip_version %d\n",
509 header->grh.ip_version);
510 return -EINVAL;
511 }
512 if (header->grh.next_header != 0x1b) {
513 pr_warn("Invalid GRH.next_header 0x%02x\n",
514 header->grh.next_header);
515 return -EINVAL;
516 }
517 break;
518
519 default:
520 pr_warn("Invalid LRH.link_next_header %d\n",
521 header->lrh.link_next_header);
522 return -EINVAL;
523 }
524
525 ib_unpack(bth_table, ARRAY_SIZE(bth_table),
526 buf, &header->bth);
527 buf = (char *)buf + IB_BTH_BYTES;
528
529 switch (header->bth.opcode) {
530 case IB_OPCODE_UD_SEND_ONLY:
531 header->immediate_present = 0;
532 break;
533 case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE:
534 header->immediate_present = 1;
535 break;
536 default:
537 pr_warn("Invalid BTH.opcode 0x%02x\n", header->bth.opcode);
538 return -EINVAL;
539 }
540
541 if (header->bth.transport_header_version != 0) {
542 pr_warn("Invalid BTH.transport_header_version %d\n",
543 header->bth.transport_header_version);
544 return -EINVAL;
545 }
546
547 ib_unpack(deth_table, ARRAY_SIZE(deth_table),
548 buf, &header->deth);
549 buf = (char *)buf + IB_DETH_BYTES;
550
551 if (header->immediate_present)
552 memcpy(&header->immediate_data, buf, sizeof header->immediate_data);
553
554 return 0;
555 }
556 EXPORT_SYMBOL(ib_ud_header_unpack);
Cache object: 7f7e28b42de182015ec696e8568163b1
|