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