xref: /linux/drivers/infiniband/core/ud_header.c (revision 3cea7b4a)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
32a1d9b7fSRoland Dreier  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * This software is available to you under a choice of one of two
61da177e4SLinus Torvalds  * licenses.  You may choose to be licensed under the terms of the GNU
71da177e4SLinus Torvalds  * General Public License (GPL) Version 2, available from the file
81da177e4SLinus Torvalds  * COPYING in the main directory of this source tree, or the
91da177e4SLinus Torvalds  * OpenIB.org BSD license below:
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  *     Redistribution and use in source and binary forms, with or
121da177e4SLinus Torvalds  *     without modification, are permitted provided that the following
131da177e4SLinus Torvalds  *     conditions are met:
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  *      - Redistributions of source code must retain the above
161da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
171da177e4SLinus Torvalds  *        disclaimer.
181da177e4SLinus Torvalds  *
191da177e4SLinus Torvalds  *      - Redistributions in binary form must reproduce the above
201da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
211da177e4SLinus Torvalds  *        disclaimer in the documentation and/or other materials
221da177e4SLinus Torvalds  *        provided with the distribution.
231da177e4SLinus Torvalds  *
241da177e4SLinus Torvalds  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
251da177e4SLinus Torvalds  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
261da177e4SLinus Torvalds  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
271da177e4SLinus Torvalds  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
281da177e4SLinus Torvalds  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
291da177e4SLinus Torvalds  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
301da177e4SLinus Torvalds  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
311da177e4SLinus Torvalds  * SOFTWARE.
321da177e4SLinus Torvalds  */
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include <linux/errno.h>
358c65b4a6STim Schmielau #include <linux/string.h>
36b108d976SPaul Gortmaker #include <linux/export.h>
37af7bd463SEli Cohen #include <linux/if_ether.h>
3825f40220SMoni Shoua #include <linux/ip.h>
391da177e4SLinus Torvalds 
40a4d61e84SRoland Dreier #include <rdma/ib_pack.h>
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds #define STRUCT_FIELD(header, field) \
431da177e4SLinus Torvalds 	.struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field),      \
44bebcfe85SGustavo A. R. Silva 	.struct_size_bytes   = sizeof_field(struct ib_unpacked_ ## header, field), \
451da177e4SLinus Torvalds 	.field_name          = #header ":" #field
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds static const struct ib_field lrh_table[]  = {
481da177e4SLinus Torvalds 	{ STRUCT_FIELD(lrh, virtual_lane),
491da177e4SLinus Torvalds 	  .offset_words = 0,
501da177e4SLinus Torvalds 	  .offset_bits  = 0,
511da177e4SLinus Torvalds 	  .size_bits    = 4 },
521da177e4SLinus Torvalds 	{ STRUCT_FIELD(lrh, link_version),
531da177e4SLinus Torvalds 	  .offset_words = 0,
541da177e4SLinus Torvalds 	  .offset_bits  = 4,
551da177e4SLinus Torvalds 	  .size_bits    = 4 },
561da177e4SLinus Torvalds 	{ STRUCT_FIELD(lrh, service_level),
571da177e4SLinus Torvalds 	  .offset_words = 0,
581da177e4SLinus Torvalds 	  .offset_bits  = 8,
591da177e4SLinus Torvalds 	  .size_bits    = 4 },
601da177e4SLinus Torvalds 	{ RESERVED,
611da177e4SLinus Torvalds 	  .offset_words = 0,
621da177e4SLinus Torvalds 	  .offset_bits  = 12,
631da177e4SLinus Torvalds 	  .size_bits    = 2 },
641da177e4SLinus Torvalds 	{ STRUCT_FIELD(lrh, link_next_header),
651da177e4SLinus Torvalds 	  .offset_words = 0,
661da177e4SLinus Torvalds 	  .offset_bits  = 14,
671da177e4SLinus Torvalds 	  .size_bits    = 2 },
681da177e4SLinus Torvalds 	{ STRUCT_FIELD(lrh, destination_lid),
691da177e4SLinus Torvalds 	  .offset_words = 0,
701da177e4SLinus Torvalds 	  .offset_bits  = 16,
711da177e4SLinus Torvalds 	  .size_bits    = 16 },
721da177e4SLinus Torvalds 	{ RESERVED,
731da177e4SLinus Torvalds 	  .offset_words = 1,
741da177e4SLinus Torvalds 	  .offset_bits  = 0,
751da177e4SLinus Torvalds 	  .size_bits    = 5 },
761da177e4SLinus Torvalds 	{ STRUCT_FIELD(lrh, packet_length),
771da177e4SLinus Torvalds 	  .offset_words = 1,
781da177e4SLinus Torvalds 	  .offset_bits  = 5,
791da177e4SLinus Torvalds 	  .size_bits    = 11 },
801da177e4SLinus Torvalds 	{ STRUCT_FIELD(lrh, source_lid),
811da177e4SLinus Torvalds 	  .offset_words = 1,
821da177e4SLinus Torvalds 	  .offset_bits  = 16,
831da177e4SLinus Torvalds 	  .size_bits    = 16 }
841da177e4SLinus Torvalds };
851da177e4SLinus Torvalds 
86ff7f5aabSEli Cohen static const struct ib_field eth_table[]  = {
87ff7f5aabSEli Cohen 	{ STRUCT_FIELD(eth, dmac_h),
88ff7f5aabSEli Cohen 	  .offset_words = 0,
89ff7f5aabSEli Cohen 	  .offset_bits  = 0,
90ff7f5aabSEli Cohen 	  .size_bits    = 32 },
91ff7f5aabSEli Cohen 	{ STRUCT_FIELD(eth, dmac_l),
92ff7f5aabSEli Cohen 	  .offset_words = 1,
93ff7f5aabSEli Cohen 	  .offset_bits  = 0,
94ff7f5aabSEli Cohen 	  .size_bits    = 16 },
95ff7f5aabSEli Cohen 	{ STRUCT_FIELD(eth, smac_h),
96ff7f5aabSEli Cohen 	  .offset_words = 1,
97ff7f5aabSEli Cohen 	  .offset_bits  = 16,
98ff7f5aabSEli Cohen 	  .size_bits    = 16 },
99ff7f5aabSEli Cohen 	{ STRUCT_FIELD(eth, smac_l),
100ff7f5aabSEli Cohen 	  .offset_words = 2,
101ff7f5aabSEli Cohen 	  .offset_bits  = 0,
102ff7f5aabSEli Cohen 	  .size_bits    = 32 },
103ff7f5aabSEli Cohen 	{ STRUCT_FIELD(eth, type),
104ff7f5aabSEli Cohen 	  .offset_words = 3,
105ff7f5aabSEli Cohen 	  .offset_bits  = 0,
106ff7f5aabSEli Cohen 	  .size_bits    = 16 }
107ff7f5aabSEli Cohen };
108ff7f5aabSEli Cohen 
109af7bd463SEli Cohen static const struct ib_field vlan_table[]  = {
110af7bd463SEli Cohen 	{ STRUCT_FIELD(vlan, tag),
111af7bd463SEli Cohen 	  .offset_words = 0,
112af7bd463SEli Cohen 	  .offset_bits  = 0,
113af7bd463SEli Cohen 	  .size_bits    = 16 },
114af7bd463SEli Cohen 	{ STRUCT_FIELD(vlan, type),
115af7bd463SEli Cohen 	  .offset_words = 0,
116af7bd463SEli Cohen 	  .offset_bits  = 16,
117af7bd463SEli Cohen 	  .size_bits    = 16 }
118af7bd463SEli Cohen };
119af7bd463SEli Cohen 
12025f40220SMoni Shoua static const struct ib_field ip4_table[]  = {
12125f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, ver),
12225f40220SMoni Shoua 	  .offset_words = 0,
12325f40220SMoni Shoua 	  .offset_bits  = 0,
12425f40220SMoni Shoua 	  .size_bits    = 4 },
12525f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, hdr_len),
12625f40220SMoni Shoua 	  .offset_words = 0,
12725f40220SMoni Shoua 	  .offset_bits  = 4,
12825f40220SMoni Shoua 	  .size_bits    = 4 },
12925f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, tos),
13025f40220SMoni Shoua 	  .offset_words = 0,
13125f40220SMoni Shoua 	  .offset_bits  = 8,
13225f40220SMoni Shoua 	  .size_bits    = 8 },
13325f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, tot_len),
13425f40220SMoni Shoua 	  .offset_words = 0,
13525f40220SMoni Shoua 	  .offset_bits  = 16,
13625f40220SMoni Shoua 	  .size_bits    = 16 },
13725f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, id),
13825f40220SMoni Shoua 	  .offset_words = 1,
13925f40220SMoni Shoua 	  .offset_bits  = 0,
14025f40220SMoni Shoua 	  .size_bits    = 16 },
14125f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, frag_off),
14225f40220SMoni Shoua 	  .offset_words = 1,
14325f40220SMoni Shoua 	  .offset_bits  = 16,
14425f40220SMoni Shoua 	  .size_bits    = 16 },
14525f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, ttl),
14625f40220SMoni Shoua 	  .offset_words = 2,
14725f40220SMoni Shoua 	  .offset_bits  = 0,
14825f40220SMoni Shoua 	  .size_bits    = 8 },
14925f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, protocol),
15025f40220SMoni Shoua 	  .offset_words = 2,
15125f40220SMoni Shoua 	  .offset_bits  = 8,
15225f40220SMoni Shoua 	  .size_bits    = 8 },
15325f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, check),
15425f40220SMoni Shoua 	  .offset_words = 2,
15525f40220SMoni Shoua 	  .offset_bits  = 16,
15625f40220SMoni Shoua 	  .size_bits    = 16 },
15725f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, saddr),
15825f40220SMoni Shoua 	  .offset_words = 3,
15925f40220SMoni Shoua 	  .offset_bits  = 0,
16025f40220SMoni Shoua 	  .size_bits    = 32 },
16125f40220SMoni Shoua 	{ STRUCT_FIELD(ip4, daddr),
16225f40220SMoni Shoua 	  .offset_words = 4,
16325f40220SMoni Shoua 	  .offset_bits  = 0,
16425f40220SMoni Shoua 	  .size_bits    = 32 }
16525f40220SMoni Shoua };
16625f40220SMoni Shoua 
16725f40220SMoni Shoua static const struct ib_field udp_table[]  = {
16825f40220SMoni Shoua 	{ STRUCT_FIELD(udp, sport),
16925f40220SMoni Shoua 	  .offset_words = 0,
17025f40220SMoni Shoua 	  .offset_bits  = 0,
17125f40220SMoni Shoua 	  .size_bits    = 16 },
17225f40220SMoni Shoua 	{ STRUCT_FIELD(udp, dport),
17325f40220SMoni Shoua 	  .offset_words = 0,
17425f40220SMoni Shoua 	  .offset_bits  = 16,
17525f40220SMoni Shoua 	  .size_bits    = 16 },
17625f40220SMoni Shoua 	{ STRUCT_FIELD(udp, length),
17725f40220SMoni Shoua 	  .offset_words = 1,
17825f40220SMoni Shoua 	  .offset_bits  = 0,
17925f40220SMoni Shoua 	  .size_bits    = 16 },
18025f40220SMoni Shoua 	{ STRUCT_FIELD(udp, csum),
18125f40220SMoni Shoua 	  .offset_words = 1,
18225f40220SMoni Shoua 	  .offset_bits  = 16,
18325f40220SMoni Shoua 	  .size_bits    = 16 }
18425f40220SMoni Shoua };
18525f40220SMoni Shoua 
1861da177e4SLinus Torvalds static const struct ib_field grh_table[]  = {
1871da177e4SLinus Torvalds 	{ STRUCT_FIELD(grh, ip_version),
1881da177e4SLinus Torvalds 	  .offset_words = 0,
1891da177e4SLinus Torvalds 	  .offset_bits  = 0,
1901da177e4SLinus Torvalds 	  .size_bits    = 4 },
1911da177e4SLinus Torvalds 	{ STRUCT_FIELD(grh, traffic_class),
1921da177e4SLinus Torvalds 	  .offset_words = 0,
1931da177e4SLinus Torvalds 	  .offset_bits  = 4,
1941da177e4SLinus Torvalds 	  .size_bits    = 8 },
1951da177e4SLinus Torvalds 	{ STRUCT_FIELD(grh, flow_label),
1961da177e4SLinus Torvalds 	  .offset_words = 0,
1971da177e4SLinus Torvalds 	  .offset_bits  = 12,
1981da177e4SLinus Torvalds 	  .size_bits    = 20 },
1991da177e4SLinus Torvalds 	{ STRUCT_FIELD(grh, payload_length),
2001da177e4SLinus Torvalds 	  .offset_words = 1,
2011da177e4SLinus Torvalds 	  .offset_bits  = 0,
2021da177e4SLinus Torvalds 	  .size_bits    = 16 },
2031da177e4SLinus Torvalds 	{ STRUCT_FIELD(grh, next_header),
2041da177e4SLinus Torvalds 	  .offset_words = 1,
2051da177e4SLinus Torvalds 	  .offset_bits  = 16,
2061da177e4SLinus Torvalds 	  .size_bits    = 8 },
2071da177e4SLinus Torvalds 	{ STRUCT_FIELD(grh, hop_limit),
2081da177e4SLinus Torvalds 	  .offset_words = 1,
2091da177e4SLinus Torvalds 	  .offset_bits  = 24,
2101da177e4SLinus Torvalds 	  .size_bits    = 8 },
2111da177e4SLinus Torvalds 	{ STRUCT_FIELD(grh, source_gid),
2121da177e4SLinus Torvalds 	  .offset_words = 2,
2131da177e4SLinus Torvalds 	  .offset_bits  = 0,
2141da177e4SLinus Torvalds 	  .size_bits    = 128 },
2151da177e4SLinus Torvalds 	{ STRUCT_FIELD(grh, destination_gid),
2161da177e4SLinus Torvalds 	  .offset_words = 6,
2171da177e4SLinus Torvalds 	  .offset_bits  = 0,
2181da177e4SLinus Torvalds 	  .size_bits    = 128 }
2191da177e4SLinus Torvalds };
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds static const struct ib_field bth_table[]  = {
2221da177e4SLinus Torvalds 	{ STRUCT_FIELD(bth, opcode),
2231da177e4SLinus Torvalds 	  .offset_words = 0,
2241da177e4SLinus Torvalds 	  .offset_bits  = 0,
2251da177e4SLinus Torvalds 	  .size_bits    = 8 },
2261da177e4SLinus Torvalds 	{ STRUCT_FIELD(bth, solicited_event),
2271da177e4SLinus Torvalds 	  .offset_words = 0,
2281da177e4SLinus Torvalds 	  .offset_bits  = 8,
2291da177e4SLinus Torvalds 	  .size_bits    = 1 },
2301da177e4SLinus Torvalds 	{ STRUCT_FIELD(bth, mig_req),
2311da177e4SLinus Torvalds 	  .offset_words = 0,
2321da177e4SLinus Torvalds 	  .offset_bits  = 9,
2331da177e4SLinus Torvalds 	  .size_bits    = 1 },
2341da177e4SLinus Torvalds 	{ STRUCT_FIELD(bth, pad_count),
2351da177e4SLinus Torvalds 	  .offset_words = 0,
2361da177e4SLinus Torvalds 	  .offset_bits  = 10,
2371da177e4SLinus Torvalds 	  .size_bits    = 2 },
2381da177e4SLinus Torvalds 	{ STRUCT_FIELD(bth, transport_header_version),
2391da177e4SLinus Torvalds 	  .offset_words = 0,
2401da177e4SLinus Torvalds 	  .offset_bits  = 12,
2411da177e4SLinus Torvalds 	  .size_bits    = 4 },
2421da177e4SLinus Torvalds 	{ STRUCT_FIELD(bth, pkey),
2431da177e4SLinus Torvalds 	  .offset_words = 0,
2441da177e4SLinus Torvalds 	  .offset_bits  = 16,
2451da177e4SLinus Torvalds 	  .size_bits    = 16 },
2461da177e4SLinus Torvalds 	{ RESERVED,
2471da177e4SLinus Torvalds 	  .offset_words = 1,
2481da177e4SLinus Torvalds 	  .offset_bits  = 0,
2491da177e4SLinus Torvalds 	  .size_bits    = 8 },
2501da177e4SLinus Torvalds 	{ STRUCT_FIELD(bth, destination_qpn),
2511da177e4SLinus Torvalds 	  .offset_words = 1,
2521da177e4SLinus Torvalds 	  .offset_bits  = 8,
2531da177e4SLinus Torvalds 	  .size_bits    = 24 },
2541da177e4SLinus Torvalds 	{ STRUCT_FIELD(bth, ack_req),
2551da177e4SLinus Torvalds 	  .offset_words = 2,
2561da177e4SLinus Torvalds 	  .offset_bits  = 0,
2571da177e4SLinus Torvalds 	  .size_bits    = 1 },
2581da177e4SLinus Torvalds 	{ RESERVED,
2591da177e4SLinus Torvalds 	  .offset_words = 2,
2601da177e4SLinus Torvalds 	  .offset_bits  = 1,
2611da177e4SLinus Torvalds 	  .size_bits    = 7 },
2621da177e4SLinus Torvalds 	{ STRUCT_FIELD(bth, psn),
2631da177e4SLinus Torvalds 	  .offset_words = 2,
2641da177e4SLinus Torvalds 	  .offset_bits  = 8,
2651da177e4SLinus Torvalds 	  .size_bits    = 24 }
2661da177e4SLinus Torvalds };
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds static const struct ib_field deth_table[] = {
2691da177e4SLinus Torvalds 	{ STRUCT_FIELD(deth, qkey),
2701da177e4SLinus Torvalds 	  .offset_words = 0,
2711da177e4SLinus Torvalds 	  .offset_bits  = 0,
2721da177e4SLinus Torvalds 	  .size_bits    = 32 },
2731da177e4SLinus Torvalds 	{ RESERVED,
2741da177e4SLinus Torvalds 	  .offset_words = 1,
2751da177e4SLinus Torvalds 	  .offset_bits  = 0,
2761da177e4SLinus Torvalds 	  .size_bits    = 8 },
2771da177e4SLinus Torvalds 	{ STRUCT_FIELD(deth, source_qpn),
2781da177e4SLinus Torvalds 	  .offset_words = 1,
2791da177e4SLinus Torvalds 	  .offset_bits  = 8,
2801da177e4SLinus Torvalds 	  .size_bits    = 24 }
2811da177e4SLinus Torvalds };
2821da177e4SLinus Torvalds 
ib_ud_ip4_csum(struct ib_ud_header * header)2833ef967a4SMoni Shoua __sum16 ib_ud_ip4_csum(struct ib_ud_header *header)
28425f40220SMoni Shoua {
28525f40220SMoni Shoua 	struct iphdr iph;
28625f40220SMoni Shoua 
28725f40220SMoni Shoua 	iph.ihl		= 5;
28825f40220SMoni Shoua 	iph.version	= 4;
28925f40220SMoni Shoua 	iph.tos		= header->ip4.tos;
29025f40220SMoni Shoua 	iph.tot_len	= header->ip4.tot_len;
29125f40220SMoni Shoua 	iph.id		= header->ip4.id;
29225f40220SMoni Shoua 	iph.frag_off	= header->ip4.frag_off;
29325f40220SMoni Shoua 	iph.ttl		= header->ip4.ttl;
29425f40220SMoni Shoua 	iph.protocol	= header->ip4.protocol;
29525f40220SMoni Shoua 	iph.check	= 0;
29625f40220SMoni Shoua 	iph.saddr	= header->ip4.saddr;
29725f40220SMoni Shoua 	iph.daddr	= header->ip4.daddr;
29825f40220SMoni Shoua 
29925f40220SMoni Shoua 	return ip_fast_csum((u8 *)&iph, iph.ihl);
30025f40220SMoni Shoua }
30125f40220SMoni Shoua EXPORT_SYMBOL(ib_ud_ip4_csum);
30225f40220SMoni Shoua 
3031da177e4SLinus Torvalds /**
3041da177e4SLinus Torvalds  * ib_ud_header_init - Initialize UD header structure
3051da177e4SLinus Torvalds  * @payload_bytes:Length of packet payload
306ff7f5aabSEli Cohen  * @lrh_present: specify if LRH is present
307ff7f5aabSEli Cohen  * @eth_present: specify if Eth header is present
308af7bd463SEli Cohen  * @vlan_present: packet is tagged vlan
3091da177e4SLinus Torvalds  * @grh_present: GRH flag (if non-zero, GRH will be included)
31025f40220SMoni Shoua  * @ip_version: if non-zero, IP header, V4 or V6, will be included
31125f40220SMoni Shoua  * @udp_present :if non-zero, UDP header will be included
312ff7f5aabSEli Cohen  * @immediate_present: specify if immediate data is present
3131da177e4SLinus Torvalds  * @header:Structure to initialize
3141da177e4SLinus Torvalds  */
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)31525f40220SMoni Shoua int ib_ud_header_init(int     payload_bytes,
316ff7f5aabSEli Cohen 		      int    lrh_present,
317ff7f5aabSEli Cohen 		      int    eth_present,
318af7bd463SEli Cohen 		      int    vlan_present,
3191da177e4SLinus Torvalds 		      int    grh_present,
32025f40220SMoni Shoua 		      int    ip_version,
32125f40220SMoni Shoua 		      int    udp_present,
322920d706cSEli Cohen 		      int    immediate_present,
3231da177e4SLinus Torvalds 		      struct ib_ud_header *header)
3241da177e4SLinus Torvalds {
3251c5e0809SMoni Shoua 	size_t udp_bytes = udp_present ? IB_UDP_BYTES : 0;
3261c5e0809SMoni Shoua 
32725f40220SMoni Shoua 	grh_present = grh_present && !ip_version;
3281da177e4SLinus Torvalds 	memset(header, 0, sizeof *header);
3291da177e4SLinus Torvalds 
33025f40220SMoni Shoua 	/*
33125f40220SMoni Shoua 	 * UDP header without IP header doesn't make sense
33225f40220SMoni Shoua 	 */
33325f40220SMoni Shoua 	if (udp_present && ip_version != 4 && ip_version != 6)
33425f40220SMoni Shoua 		return -EINVAL;
33525f40220SMoni Shoua 
336ff7f5aabSEli Cohen 	if (lrh_present) {
337ff7f5aabSEli Cohen 		u16 packet_length;
338ff7f5aabSEli Cohen 
3391da177e4SLinus Torvalds 		header->lrh.link_version     = 0;
3401da177e4SLinus Torvalds 		header->lrh.link_next_header =
3411da177e4SLinus Torvalds 			grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
34297f52eb4SSean Hefty 		packet_length = (IB_LRH_BYTES	+
3431da177e4SLinus Torvalds 				 IB_BTH_BYTES	+
3441da177e4SLinus Torvalds 				 IB_DETH_BYTES	+
345ff7f5aabSEli Cohen 				 (grh_present ? IB_GRH_BYTES : 0) +
3461da177e4SLinus Torvalds 				 payload_bytes	+
3471da177e4SLinus Torvalds 				 4		+ /* ICRC     */
3481da177e4SLinus Torvalds 				 3) / 4;	  /* round up */
349ff7f5aabSEli Cohen 		header->lrh.packet_length = cpu_to_be16(packet_length);
350ff7f5aabSEli Cohen 	}
3511da177e4SLinus Torvalds 
352af7bd463SEli Cohen 	if (vlan_present)
353af7bd463SEli Cohen 		header->eth.type = cpu_to_be16(ETH_P_8021Q);
354af7bd463SEli Cohen 
35525f40220SMoni Shoua 	if (ip_version == 6 || grh_present) {
3561da177e4SLinus Torvalds 		header->grh.ip_version      = 6;
3571da177e4SLinus Torvalds 		header->grh.payload_length  =
3581c5e0809SMoni Shoua 			cpu_to_be16((udp_bytes        +
3591c5e0809SMoni Shoua 				     IB_BTH_BYTES     +
3601da177e4SLinus Torvalds 				     IB_DETH_BYTES    +
3611da177e4SLinus Torvalds 				     payload_bytes    +
3621da177e4SLinus Torvalds 				     4                + /* ICRC     */
3631da177e4SLinus Torvalds 				     3) & ~3);          /* round up */
36425f40220SMoni Shoua 		header->grh.next_header     = udp_present ? IPPROTO_UDP : 0x1b;
3651da177e4SLinus Torvalds 	}
3661da177e4SLinus Torvalds 
36725f40220SMoni Shoua 	if (ip_version == 4) {
36825f40220SMoni Shoua 		header->ip4.ver = 4; /* version 4 */
36925f40220SMoni Shoua 		header->ip4.hdr_len = 5; /* 5 words */
37025f40220SMoni Shoua 		header->ip4.tot_len =
37125f40220SMoni Shoua 			cpu_to_be16(IB_IP4_BYTES   +
37225f40220SMoni Shoua 				     udp_bytes     +
37325f40220SMoni Shoua 				     IB_BTH_BYTES  +
37425f40220SMoni Shoua 				     IB_DETH_BYTES +
37525f40220SMoni Shoua 				     payload_bytes +
37625f40220SMoni Shoua 				     4);     /* ICRC     */
37725f40220SMoni Shoua 		header->ip4.protocol = IPPROTO_UDP;
37825f40220SMoni Shoua 	}
37925f40220SMoni Shoua 	if (udp_present && ip_version)
38025f40220SMoni Shoua 		header->udp.length =
38125f40220SMoni Shoua 			cpu_to_be16(IB_UDP_BYTES   +
38225f40220SMoni Shoua 				     IB_BTH_BYTES  +
38325f40220SMoni Shoua 				     IB_DETH_BYTES +
38425f40220SMoni Shoua 				     payload_bytes +
38525f40220SMoni Shoua 				     4);     /* ICRC     */
38625f40220SMoni Shoua 
387920d706cSEli Cohen 	if (immediate_present)
3881da177e4SLinus Torvalds 		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
3891da177e4SLinus Torvalds 	else
3901da177e4SLinus Torvalds 		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY;
3911da177e4SLinus Torvalds 	header->bth.pad_count                = (4 - payload_bytes) & 3;
3921da177e4SLinus Torvalds 	header->bth.transport_header_version = 0;
393ff7f5aabSEli Cohen 
394ff7f5aabSEli Cohen 	header->lrh_present = lrh_present;
395ff7f5aabSEli Cohen 	header->eth_present = eth_present;
396af7bd463SEli Cohen 	header->vlan_present = vlan_present;
39725f40220SMoni Shoua 	header->grh_present = grh_present || (ip_version == 6);
39825f40220SMoni Shoua 	header->ipv4_present = ip_version == 4;
39925f40220SMoni Shoua 	header->udp_present = udp_present;
400ff7f5aabSEli Cohen 	header->immediate_present = immediate_present;
40125f40220SMoni Shoua 	return 0;
4021da177e4SLinus Torvalds }
4031da177e4SLinus Torvalds EXPORT_SYMBOL(ib_ud_header_init);
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds /**
4061da177e4SLinus Torvalds  * ib_ud_header_pack - Pack UD header struct into wire format
4071da177e4SLinus Torvalds  * @header:UD header struct
4081da177e4SLinus Torvalds  * @buf:Buffer to pack into
4091da177e4SLinus Torvalds  *
4101da177e4SLinus Torvalds  * ib_ud_header_pack() packs the UD header structure @header into wire
4111da177e4SLinus Torvalds  * format in the buffer @buf.
4121da177e4SLinus Torvalds  */
ib_ud_header_pack(struct ib_ud_header * header,void * buf)4131da177e4SLinus Torvalds int ib_ud_header_pack(struct ib_ud_header *header,
4141da177e4SLinus Torvalds 		      void                *buf)
4151da177e4SLinus Torvalds {
4161da177e4SLinus Torvalds 	int len = 0;
4171da177e4SLinus Torvalds 
418ff7f5aabSEli Cohen 	if (header->lrh_present) {
4191da177e4SLinus Torvalds 		ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
420ff7f5aabSEli Cohen 			&header->lrh, buf + len);
4211da177e4SLinus Torvalds 		len += IB_LRH_BYTES;
422ff7f5aabSEli Cohen 	}
423ff7f5aabSEli Cohen 	if (header->eth_present) {
424ff7f5aabSEli Cohen 		ib_pack(eth_table, ARRAY_SIZE(eth_table),
425ff7f5aabSEli Cohen 			&header->eth, buf + len);
426ff7f5aabSEli Cohen 		len += IB_ETH_BYTES;
427ff7f5aabSEli Cohen 	}
428af7bd463SEli Cohen 	if (header->vlan_present) {
429af7bd463SEli Cohen 		ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
430af7bd463SEli Cohen 			&header->vlan, buf + len);
431af7bd463SEli Cohen 		len += IB_VLAN_BYTES;
432af7bd463SEli Cohen 	}
4331da177e4SLinus Torvalds 	if (header->grh_present) {
4341da177e4SLinus Torvalds 		ib_pack(grh_table, ARRAY_SIZE(grh_table),
4351da177e4SLinus Torvalds 			&header->grh, buf + len);
4361da177e4SLinus Torvalds 		len += IB_GRH_BYTES;
4371da177e4SLinus Torvalds 	}
43825f40220SMoni Shoua 	if (header->ipv4_present) {
43925f40220SMoni Shoua 		ib_pack(ip4_table, ARRAY_SIZE(ip4_table),
44025f40220SMoni Shoua 			&header->ip4, buf + len);
44125f40220SMoni Shoua 		len += IB_IP4_BYTES;
44225f40220SMoni Shoua 	}
44325f40220SMoni Shoua 	if (header->udp_present) {
44425f40220SMoni Shoua 		ib_pack(udp_table, ARRAY_SIZE(udp_table),
44525f40220SMoni Shoua 			&header->udp, buf + len);
44625f40220SMoni Shoua 		len += IB_UDP_BYTES;
44725f40220SMoni Shoua 	}
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds 	ib_pack(bth_table, ARRAY_SIZE(bth_table),
4501da177e4SLinus Torvalds 		&header->bth, buf + len);
4511da177e4SLinus Torvalds 	len += IB_BTH_BYTES;
4521da177e4SLinus Torvalds 
4531da177e4SLinus Torvalds 	ib_pack(deth_table, ARRAY_SIZE(deth_table),
4541da177e4SLinus Torvalds 		&header->deth, buf + len);
4551da177e4SLinus Torvalds 	len += IB_DETH_BYTES;
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds 	if (header->immediate_present) {
4581da177e4SLinus Torvalds 		memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data);
4591da177e4SLinus Torvalds 		len += sizeof header->immediate_data;
4601da177e4SLinus Torvalds 	}
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	return len;
4631da177e4SLinus Torvalds }
4641da177e4SLinus Torvalds EXPORT_SYMBOL(ib_ud_header_pack);
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds /**
4671da177e4SLinus Torvalds  * ib_ud_header_unpack - Unpack UD header struct from wire format
4681da177e4SLinus Torvalds  * @header:UD header struct
4691da177e4SLinus Torvalds  * @buf:Buffer to pack into
4701da177e4SLinus Torvalds  *
4711da177e4SLinus Torvalds  * ib_ud_header_pack() unpacks the UD header structure @header from wire
4721da177e4SLinus Torvalds  * format in the buffer @buf.
4731da177e4SLinus Torvalds  */
ib_ud_header_unpack(void * buf,struct ib_ud_header * header)4741da177e4SLinus Torvalds int ib_ud_header_unpack(void                *buf,
4751da177e4SLinus Torvalds 			struct ib_ud_header *header)
4761da177e4SLinus Torvalds {
4771da177e4SLinus Torvalds 	ib_unpack(lrh_table, ARRAY_SIZE(lrh_table),
4781da177e4SLinus Torvalds 		  buf, &header->lrh);
4791da177e4SLinus Torvalds 	buf += IB_LRH_BYTES;
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 	if (header->lrh.link_version != 0) {
482*3cea7b4aSWenpeng Liang 		pr_warn("Invalid LRH.link_version %u\n",
4831da177e4SLinus Torvalds 			header->lrh.link_version);
4841da177e4SLinus Torvalds 		return -EINVAL;
4851da177e4SLinus Torvalds 	}
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	switch (header->lrh.link_next_header) {
4881da177e4SLinus Torvalds 	case IB_LNH_IBA_LOCAL:
4891da177e4SLinus Torvalds 		header->grh_present = 0;
4901da177e4SLinus Torvalds 		break;
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 	case IB_LNH_IBA_GLOBAL:
4931da177e4SLinus Torvalds 		header->grh_present = 1;
4941da177e4SLinus Torvalds 		ib_unpack(grh_table, ARRAY_SIZE(grh_table),
4951da177e4SLinus Torvalds 			  buf, &header->grh);
4961da177e4SLinus Torvalds 		buf += IB_GRH_BYTES;
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 		if (header->grh.ip_version != 6) {
499*3cea7b4aSWenpeng Liang 			pr_warn("Invalid GRH.ip_version %u\n",
5001da177e4SLinus Torvalds 				header->grh.ip_version);
5011da177e4SLinus Torvalds 			return -EINVAL;
5021da177e4SLinus Torvalds 		}
5031da177e4SLinus Torvalds 		if (header->grh.next_header != 0x1b) {
504aba25a3eSParav Pandit 			pr_warn("Invalid GRH.next_header 0x%02x\n",
5051da177e4SLinus Torvalds 				header->grh.next_header);
5061da177e4SLinus Torvalds 			return -EINVAL;
5071da177e4SLinus Torvalds 		}
5081da177e4SLinus Torvalds 		break;
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds 	default:
511*3cea7b4aSWenpeng Liang 		pr_warn("Invalid LRH.link_next_header %u\n",
5121da177e4SLinus Torvalds 			header->lrh.link_next_header);
5131da177e4SLinus Torvalds 		return -EINVAL;
5141da177e4SLinus Torvalds 	}
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds 	ib_unpack(bth_table, ARRAY_SIZE(bth_table),
5171da177e4SLinus Torvalds 		  buf, &header->bth);
5181da177e4SLinus Torvalds 	buf += IB_BTH_BYTES;
5191da177e4SLinus Torvalds 
5201da177e4SLinus Torvalds 	switch (header->bth.opcode) {
5211da177e4SLinus Torvalds 	case IB_OPCODE_UD_SEND_ONLY:
5221da177e4SLinus Torvalds 		header->immediate_present = 0;
5231da177e4SLinus Torvalds 		break;
5241da177e4SLinus Torvalds 	case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE:
5251da177e4SLinus Torvalds 		header->immediate_present = 1;
5261da177e4SLinus Torvalds 		break;
5271da177e4SLinus Torvalds 	default:
528aba25a3eSParav Pandit 		pr_warn("Invalid BTH.opcode 0x%02x\n", header->bth.opcode);
5291da177e4SLinus Torvalds 		return -EINVAL;
5301da177e4SLinus Torvalds 	}
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 	if (header->bth.transport_header_version != 0) {
533*3cea7b4aSWenpeng Liang 		pr_warn("Invalid BTH.transport_header_version %u\n",
5341da177e4SLinus Torvalds 			header->bth.transport_header_version);
5351da177e4SLinus Torvalds 		return -EINVAL;
5361da177e4SLinus Torvalds 	}
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 	ib_unpack(deth_table, ARRAY_SIZE(deth_table),
5391da177e4SLinus Torvalds 		  buf, &header->deth);
5401da177e4SLinus Torvalds 	buf += IB_DETH_BYTES;
5411da177e4SLinus Torvalds 
5421da177e4SLinus Torvalds 	if (header->immediate_present)
5431da177e4SLinus Torvalds 		memcpy(&header->immediate_data, buf, sizeof header->immediate_data);
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds 	return 0;
5461da177e4SLinus Torvalds }
5471da177e4SLinus Torvalds EXPORT_SYMBOL(ib_ud_header_unpack);
548