xref: /freebsd/sys/ofed/drivers/infiniband/core/ib_ud_header.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
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