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