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/if_ether.h>
37
38#include <rdma/ib_pack.h>
39
40#define STRUCT_FIELD(header, field) \
41	.struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field),      \
42	.struct_size_bytes   = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \
43	.field_name          = #header ":" #field
44
45static const struct ib_field lrh_table[]  = {
46	{ STRUCT_FIELD(lrh, virtual_lane),
47	  .offset_words = 0,
48	  .offset_bits  = 0,
49	  .size_bits    = 4 },
50	{ STRUCT_FIELD(lrh, link_version),
51	  .offset_words = 0,
52	  .offset_bits  = 4,
53	  .size_bits    = 4 },
54	{ STRUCT_FIELD(lrh, service_level),
55	  .offset_words = 0,
56	  .offset_bits  = 8,
57	  .size_bits    = 4 },
58	{ RESERVED,
59	  .offset_words = 0,
60	  .offset_bits  = 12,
61	  .size_bits    = 2 },
62	{ STRUCT_FIELD(lrh, link_next_header),
63	  .offset_words = 0,
64	  .offset_bits  = 14,
65	  .size_bits    = 2 },
66	{ STRUCT_FIELD(lrh, destination_lid),
67	  .offset_words = 0,
68	  .offset_bits  = 16,
69	  .size_bits    = 16 },
70	{ RESERVED,
71	  .offset_words = 1,
72	  .offset_bits  = 0,
73	  .size_bits    = 5 },
74	{ STRUCT_FIELD(lrh, packet_length),
75	  .offset_words = 1,
76	  .offset_bits  = 5,
77	  .size_bits    = 11 },
78	{ STRUCT_FIELD(lrh, source_lid),
79	  .offset_words = 1,
80	  .offset_bits  = 16,
81	  .size_bits    = 16 }
82};
83
84static const struct ib_field eth_table[]  = {
85	{ STRUCT_FIELD(eth, dmac_h),
86	  .offset_words = 0,
87	  .offset_bits  = 0,
88	  .size_bits    = 32 },
89	{ STRUCT_FIELD(eth, dmac_l),
90	  .offset_words = 1,
91	  .offset_bits  = 0,
92	  .size_bits    = 16 },
93	{ STRUCT_FIELD(eth, smac_h),
94	  .offset_words = 1,
95	  .offset_bits  = 16,
96	  .size_bits    = 16 },
97	{ STRUCT_FIELD(eth, smac_l),
98	  .offset_words = 2,
99	  .offset_bits  = 0,
100	  .size_bits    = 32 },
101	{ STRUCT_FIELD(eth, type),
102	  .offset_words = 3,
103	  .offset_bits  = 0,
104	  .size_bits    = 16 }
105};
106
107static const struct ib_field vlan_table[]  = {
108	{ STRUCT_FIELD(vlan, tag),
109	  .offset_words = 0,
110	  .offset_bits  = 0,
111	  .size_bits    = 16 },
112	{ STRUCT_FIELD(vlan, type),
113	  .offset_words = 0,
114	  .offset_bits  = 16,
115	  .size_bits    = 16 }
116};
117
118static const struct ib_field grh_table[]  = {
119	{ STRUCT_FIELD(grh, ip_version),
120	  .offset_words = 0,
121	  .offset_bits  = 0,
122	  .size_bits    = 4 },
123	{ STRUCT_FIELD(grh, traffic_class),
124	  .offset_words = 0,
125	  .offset_bits  = 4,
126	  .size_bits    = 8 },
127	{ STRUCT_FIELD(grh, flow_label),
128	  .offset_words = 0,
129	  .offset_bits  = 12,
130	  .size_bits    = 20 },
131	{ STRUCT_FIELD(grh, payload_length),
132	  .offset_words = 1,
133	  .offset_bits  = 0,
134	  .size_bits    = 16 },
135	{ STRUCT_FIELD(grh, next_header),
136	  .offset_words = 1,
137	  .offset_bits  = 16,
138	  .size_bits    = 8 },
139	{ STRUCT_FIELD(grh, hop_limit),
140	  .offset_words = 1,
141	  .offset_bits  = 24,
142	  .size_bits    = 8 },
143	{ STRUCT_FIELD(grh, source_gid),
144	  .offset_words = 2,
145	  .offset_bits  = 0,
146	  .size_bits    = 128 },
147	{ STRUCT_FIELD(grh, destination_gid),
148	  .offset_words = 6,
149	  .offset_bits  = 0,
150	  .size_bits    = 128 }
151};
152
153static const struct ib_field bth_table[]  = {
154	{ STRUCT_FIELD(bth, opcode),
155	  .offset_words = 0,
156	  .offset_bits  = 0,
157	  .size_bits    = 8 },
158	{ STRUCT_FIELD(bth, solicited_event),
159	  .offset_words = 0,
160	  .offset_bits  = 8,
161	  .size_bits    = 1 },
162	{ STRUCT_FIELD(bth, mig_req),
163	  .offset_words = 0,
164	  .offset_bits  = 9,
165	  .size_bits    = 1 },
166	{ STRUCT_FIELD(bth, pad_count),
167	  .offset_words = 0,
168	  .offset_bits  = 10,
169	  .size_bits    = 2 },
170	{ STRUCT_FIELD(bth, transport_header_version),
171	  .offset_words = 0,
172	  .offset_bits  = 12,
173	  .size_bits    = 4 },
174	{ STRUCT_FIELD(bth, pkey),
175	  .offset_words = 0,
176	  .offset_bits  = 16,
177	  .size_bits    = 16 },
178	{ RESERVED,
179	  .offset_words = 1,
180	  .offset_bits  = 0,
181	  .size_bits    = 8 },
182	{ STRUCT_FIELD(bth, destination_qpn),
183	  .offset_words = 1,
184	  .offset_bits  = 8,
185	  .size_bits    = 24 },
186	{ STRUCT_FIELD(bth, ack_req),
187	  .offset_words = 2,
188	  .offset_bits  = 0,
189	  .size_bits    = 1 },
190	{ RESERVED,
191	  .offset_words = 2,
192	  .offset_bits  = 1,
193	  .size_bits    = 7 },
194	{ STRUCT_FIELD(bth, psn),
195	  .offset_words = 2,
196	  .offset_bits  = 8,
197	  .size_bits    = 24 }
198};
199
200static const struct ib_field deth_table[] = {
201	{ STRUCT_FIELD(deth, qkey),
202	  .offset_words = 0,
203	  .offset_bits  = 0,
204	  .size_bits    = 32 },
205	{ RESERVED,
206	  .offset_words = 1,
207	  .offset_bits  = 0,
208	  .size_bits    = 8 },
209	{ STRUCT_FIELD(deth, source_qpn),
210	  .offset_words = 1,
211	  .offset_bits  = 8,
212	  .size_bits    = 24 }
213};
214
215/**
216 * ib_ud_header_init - Initialize UD header structure
217 * @payload_bytes:Length of packet payload
218 * @lrh_present: specify if LRH is present
219 * @eth_present: specify if Eth header is present
220 * @vlan_present: packet is tagged vlan
221 * @grh_present:GRH flag (if non-zero, GRH will be included)
222 * @immediate_present: specify if immediate data is present
223 * @header:Structure to initialize
224 */
225void ib_ud_header_init(int     		    payload_bytes,
226		       int		    lrh_present,
227		       int		    eth_present,
228		       int		    vlan_present,
229		       int    		    grh_present,
230		       int		    immediate_present,
231		       struct ib_ud_header *header)
232{
233	u16 packet_length = 0;
234
235	memset(header, 0, sizeof *header);
236
237	if (lrh_present) {
238		header->lrh.link_version     = 0;
239		header->lrh.link_next_header =
240			grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
241		packet_length = IB_LRH_BYTES;
242	}
243
244	if (eth_present) {
245		if (vlan_present) {
246			header->eth.type = cpu_to_be16(ETH_P_8021Q);
247			packet_length += IB_VLAN_BYTES;
248
249		}
250		packet_length += IB_ETH_BYTES;
251	}
252
253	packet_length += IB_BTH_BYTES + IB_DETH_BYTES + payload_bytes +
254		4       + /* ICRC     */
255		3;        /* round up */
256	packet_length /= 4;
257	if (grh_present) {
258		packet_length += IB_GRH_BYTES / 4;
259		header->grh.ip_version = 6;
260		header->grh.payload_length =
261			cpu_to_be16((IB_BTH_BYTES  +
262				     IB_DETH_BYTES +
263				     payload_bytes +
264				     4             + /* ICRC     */
265				     3) & ~3);       /* round up */
266		header->grh.next_header     = 0x1b;
267	}
268
269	if (lrh_present)
270		header->lrh.packet_length = cpu_to_be16(packet_length);
271
272	if (immediate_present)
273		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
274	else
275		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY;
276	header->bth.pad_count                = (4 - payload_bytes) & 3;
277	header->bth.transport_header_version = 0;
278
279	header->lrh_present = lrh_present;
280	header->eth_present = eth_present;
281	header->vlan_present = vlan_present;
282	header->grh_present = grh_present;
283	header->immediate_present = immediate_present;
284}
285EXPORT_SYMBOL(ib_ud_header_init);
286
287/**
288 * ib_lrh_header_pack - Pack LRH header struct into wire format
289 * @lrh:unpacked LRH header struct
290 * @buf:Buffer to pack into
291 *
292 * ib_lrh_header_pack() packs the LRH header structure @lrh into
293 * wire format in the buffer @buf.
294 */
295int ib_lrh_header_pack(struct ib_unpacked_lrh *lrh, void *buf)
296{
297	ib_pack(lrh_table, ARRAY_SIZE(lrh_table), lrh, buf);
298	return 0;
299}
300EXPORT_SYMBOL(ib_lrh_header_pack);
301
302/**
303 * ib_lrh_header_unpack - Unpack LRH structure from wire format
304 * @lrh:unpacked LRH header struct
305 * @buf:Buffer to pack into
306 *
307 * ib_lrh_header_unpack() unpacks the LRH header structure from
308 * wire format (in buf) into @lrh.
309 */
310int ib_lrh_header_unpack(void *buf, struct ib_unpacked_lrh *lrh)
311{
312	ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), buf, lrh);
313	return 0;
314}
315EXPORT_SYMBOL(ib_lrh_header_unpack);
316
317/**
318 * ib_ud_header_pack - Pack UD header struct into wire format
319 * @header:UD header struct
320 * @buf:Buffer to pack into
321 *
322 * ib_ud_header_pack() packs the UD header structure @header into wire
323 * format in the buffer @buf.
324 */
325int ib_ud_header_pack(struct ib_ud_header *header,
326		      void                *buf)
327{
328	int len = 0;
329
330	if (header->lrh_present) {
331		ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
332			&header->lrh, buf + len);
333		len += IB_LRH_BYTES;
334	}
335	if (header->eth_present) {
336		ib_pack(eth_table, ARRAY_SIZE(eth_table),
337			&header->eth, buf + len);
338		len += IB_ETH_BYTES;
339	}
340
341
342	if (header->vlan_present) {
343		ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
344			&header->vlan, buf + len);
345		len += IB_VLAN_BYTES;
346	}
347
348	if (header->grh_present) {
349		ib_pack(grh_table, ARRAY_SIZE(grh_table),
350			&header->grh, buf + len);
351		len += IB_GRH_BYTES;
352	}
353
354	ib_pack(bth_table, ARRAY_SIZE(bth_table),
355		&header->bth, buf + len);
356	len += IB_BTH_BYTES;
357
358	ib_pack(deth_table, ARRAY_SIZE(deth_table),
359		&header->deth, buf + len);
360	len += IB_DETH_BYTES;
361
362	if (header->immediate_present) {
363		memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data);
364		len += sizeof header->immediate_data;
365	}
366
367	return len;
368}
369EXPORT_SYMBOL(ib_ud_header_pack);
370
371/**
372 * ib_ud_header_unpack - Unpack UD header struct from wire format
373 * @header:UD header struct
374 * @buf:Buffer to pack into
375 *
376 * ib_ud_header_pack() unpacks the UD header structure @header from wire
377 * format in the buffer @buf.
378 */
379int ib_ud_header_unpack(void                *buf,
380			struct ib_ud_header *header)
381{
382	ib_unpack(lrh_table, ARRAY_SIZE(lrh_table),
383		  buf, &header->lrh);
384	buf += IB_LRH_BYTES;
385
386	if (header->lrh.link_version != 0) {
387		printk(KERN_WARNING "Invalid LRH.link_version %d\n",
388		       header->lrh.link_version);
389		return -EINVAL;
390	}
391
392	switch (header->lrh.link_next_header) {
393	case IB_LNH_IBA_LOCAL:
394		header->grh_present = 0;
395		break;
396
397	case IB_LNH_IBA_GLOBAL:
398		header->grh_present = 1;
399		ib_unpack(grh_table, ARRAY_SIZE(grh_table),
400			  buf, &header->grh);
401		buf += IB_GRH_BYTES;
402
403		if (header->grh.ip_version != 6) {
404			printk(KERN_WARNING "Invalid GRH.ip_version %d\n",
405			       header->grh.ip_version);
406			return -EINVAL;
407		}
408		if (header->grh.next_header != 0x1b) {
409			printk(KERN_WARNING "Invalid GRH.next_header 0x%02x\n",
410			       header->grh.next_header);
411			return -EINVAL;
412		}
413		break;
414
415	default:
416		printk(KERN_WARNING "Invalid LRH.link_next_header %d\n",
417		       header->lrh.link_next_header);
418		return -EINVAL;
419	}
420
421	ib_unpack(bth_table, ARRAY_SIZE(bth_table),
422		  buf, &header->bth);
423	buf += IB_BTH_BYTES;
424
425	switch (header->bth.opcode) {
426	case IB_OPCODE_UD_SEND_ONLY:
427		header->immediate_present = 0;
428		break;
429	case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE:
430		header->immediate_present = 1;
431		break;
432	default:
433		printk(KERN_WARNING "Invalid BTH.opcode 0x%02x\n",
434		       header->bth.opcode);
435		return -EINVAL;
436	}
437
438	if (header->bth.transport_header_version != 0) {
439		printk(KERN_WARNING "Invalid BTH.transport_header_version %d\n",
440		       header->bth.transport_header_version);
441		return -EINVAL;
442	}
443
444	ib_unpack(deth_table, ARRAY_SIZE(deth_table),
445		  buf, &header->deth);
446	buf += IB_DETH_BYTES;
447
448	if (header->immediate_present)
449		memcpy(&header->immediate_data, buf, sizeof header->immediate_data);
450
451	return 0;
452}
453EXPORT_SYMBOL(ib_ud_header_unpack);
454