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