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: stable/11/sys/ofed/drivers/infiniband/core/ib_ud_header.c 337096 2018-08-02 08:33:51Z hselasky $");
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
52static 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
91static 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
114static 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
125static 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
172static 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
191static 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
226static 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
273static 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}
310EXPORT_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 */
324int 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}
412EXPORT_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 */
422int 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}
473EXPORT_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 */
483int 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}
556EXPORT_SYMBOL(ib_ud_header_unpack);
557