Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ud_header.c
Go to the documentation of this file.
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 
39 #include <rdma/ib_pack.h>
40 
41 #define STRUCT_FIELD(header, field) \
42  .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \
43  .struct_size_bytes = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \
44  .field_name = #header ":" #field
45 
46 static const struct ib_field lrh_table[] = {
47  { STRUCT_FIELD(lrh, virtual_lane),
48  .offset_words = 0,
49  .offset_bits = 0,
50  .size_bits = 4 },
51  { STRUCT_FIELD(lrh, link_version),
52  .offset_words = 0,
53  .offset_bits = 4,
54  .size_bits = 4 },
56  .offset_words = 0,
57  .offset_bits = 8,
58  .size_bits = 4 },
59  { RESERVED,
60  .offset_words = 0,
61  .offset_bits = 12,
62  .size_bits = 2 },
63  { STRUCT_FIELD(lrh, link_next_header),
64  .offset_words = 0,
65  .offset_bits = 14,
66  .size_bits = 2 },
67  { STRUCT_FIELD(lrh, destination_lid),
68  .offset_words = 0,
69  .offset_bits = 16,
70  .size_bits = 16 },
71  { RESERVED,
72  .offset_words = 1,
73  .offset_bits = 0,
74  .size_bits = 5 },
75  { STRUCT_FIELD(lrh, packet_length),
76  .offset_words = 1,
77  .offset_bits = 5,
78  .size_bits = 11 },
79  { STRUCT_FIELD(lrh, source_lid),
80  .offset_words = 1,
81  .offset_bits = 16,
82  .size_bits = 16 }
83 };
84 
85 static const struct ib_field eth_table[] = {
86  { STRUCT_FIELD(eth, dmac_h),
87  .offset_words = 0,
88  .offset_bits = 0,
89  .size_bits = 32 },
90  { STRUCT_FIELD(eth, dmac_l),
91  .offset_words = 1,
92  .offset_bits = 0,
93  .size_bits = 16 },
94  { STRUCT_FIELD(eth, smac_h),
95  .offset_words = 1,
96  .offset_bits = 16,
97  .size_bits = 16 },
98  { STRUCT_FIELD(eth, smac_l),
99  .offset_words = 2,
100  .offset_bits = 0,
101  .size_bits = 32 },
102  { STRUCT_FIELD(eth, type),
103  .offset_words = 3,
104  .offset_bits = 0,
105  .size_bits = 16 }
106 };
107 
108 static const struct ib_field vlan_table[] = {
109  { STRUCT_FIELD(vlan, tag),
110  .offset_words = 0,
111  .offset_bits = 0,
112  .size_bits = 16 },
113  { STRUCT_FIELD(vlan, type),
114  .offset_words = 0,
115  .offset_bits = 16,
116  .size_bits = 16 }
117 };
118 
119 static const struct ib_field grh_table[] = {
121  .offset_words = 0,
122  .offset_bits = 0,
123  .size_bits = 4 },
124  { STRUCT_FIELD(grh, traffic_class),
125  .offset_words = 0,
126  .offset_bits = 4,
127  .size_bits = 8 },
128  { STRUCT_FIELD(grh, flow_label),
129  .offset_words = 0,
130  .offset_bits = 12,
131  .size_bits = 20 },
133  .offset_words = 1,
134  .offset_bits = 0,
135  .size_bits = 16 },
136  { STRUCT_FIELD(grh, next_header),
137  .offset_words = 1,
138  .offset_bits = 16,
139  .size_bits = 8 },
141  .offset_words = 1,
142  .offset_bits = 24,
143  .size_bits = 8 },
144  { STRUCT_FIELD(grh, source_gid),
145  .offset_words = 2,
146  .offset_bits = 0,
147  .size_bits = 128 },
148  { STRUCT_FIELD(grh, destination_gid),
149  .offset_words = 6,
150  .offset_bits = 0,
151  .size_bits = 128 }
152 };
153 
154 static const struct ib_field bth_table[] = {
155  { STRUCT_FIELD(bth, opcode),
156  .offset_words = 0,
157  .offset_bits = 0,
158  .size_bits = 8 },
159  { STRUCT_FIELD(bth, solicited_event),
160  .offset_words = 0,
161  .offset_bits = 8,
162  .size_bits = 1 },
163  { STRUCT_FIELD(bth, mig_req),
164  .offset_words = 0,
165  .offset_bits = 9,
166  .size_bits = 1 },
167  { STRUCT_FIELD(bth, pad_count),
168  .offset_words = 0,
169  .offset_bits = 10,
170  .size_bits = 2 },
171  { STRUCT_FIELD(bth, transport_header_version),
172  .offset_words = 0,
173  .offset_bits = 12,
174  .size_bits = 4 },
175  { STRUCT_FIELD(bth, pkey),
176  .offset_words = 0,
177  .offset_bits = 16,
178  .size_bits = 16 },
179  { RESERVED,
180  .offset_words = 1,
181  .offset_bits = 0,
182  .size_bits = 8 },
183  { STRUCT_FIELD(bth, destination_qpn),
184  .offset_words = 1,
185  .offset_bits = 8,
186  .size_bits = 24 },
187  { STRUCT_FIELD(bth, ack_req),
188  .offset_words = 2,
189  .offset_bits = 0,
190  .size_bits = 1 },
191  { RESERVED,
192  .offset_words = 2,
193  .offset_bits = 1,
194  .size_bits = 7 },
195  { STRUCT_FIELD(bth, psn),
196  .offset_words = 2,
197  .offset_bits = 8,
198  .size_bits = 24 }
199 };
200 
201 static const struct ib_field deth_table[] = {
202  { STRUCT_FIELD(deth, qkey),
203  .offset_words = 0,
204  .offset_bits = 0,
205  .size_bits = 32 },
206  { RESERVED,
207  .offset_words = 1,
208  .offset_bits = 0,
209  .size_bits = 8 },
210  { STRUCT_FIELD(deth, source_qpn),
211  .offset_words = 1,
212  .offset_bits = 8,
213  .size_bits = 24 }
214 };
215 
226 void ib_ud_header_init(int payload_bytes,
227  int lrh_present,
228  int eth_present,
229  int vlan_present,
230  int grh_present,
231  int immediate_present,
232  struct ib_ud_header *header)
233 {
234  memset(header, 0, sizeof *header);
235 
236  if (lrh_present) {
237  u16 packet_length;
238 
239  header->lrh.link_version = 0;
240  header->lrh.link_next_header =
241  grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
242  packet_length = (IB_LRH_BYTES +
243  IB_BTH_BYTES +
244  IB_DETH_BYTES +
245  (grh_present ? IB_GRH_BYTES : 0) +
246  payload_bytes +
247  4 + /* ICRC */
248  3) / 4; /* round up */
249  header->lrh.packet_length = cpu_to_be16(packet_length);
250  }
251 
252  if (vlan_present)
253  header->eth.type = cpu_to_be16(ETH_P_8021Q);
254 
255  if (grh_present) {
256  header->grh.ip_version = 6;
257  header->grh.payload_length =
259  IB_DETH_BYTES +
260  payload_bytes +
261  4 + /* ICRC */
262  3) & ~3); /* round up */
263  header->grh.next_header = 0x1b;
264  }
265 
266  if (immediate_present)
267  header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
268  else
269  header->bth.opcode = IB_OPCODE_UD_SEND_ONLY;
270  header->bth.pad_count = (4 - payload_bytes) & 3;
271  header->bth.transport_header_version = 0;
272 
273  header->lrh_present = lrh_present;
274  header->eth_present = eth_present;
275  header->vlan_present = vlan_present;
276  header->grh_present = grh_present;
277  header->immediate_present = immediate_present;
278 }
280 
290  void *buf)
291 {
292  int len = 0;
293 
294  if (header->lrh_present) {
295  ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
296  &header->lrh, buf + len);
297  len += IB_LRH_BYTES;
298  }
299  if (header->eth_present) {
300  ib_pack(eth_table, ARRAY_SIZE(eth_table),
301  &header->eth, buf + len);
302  len += IB_ETH_BYTES;
303  }
304  if (header->vlan_present) {
305  ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
306  &header->vlan, buf + len);
307  len += IB_VLAN_BYTES;
308  }
309  if (header->grh_present) {
310  ib_pack(grh_table, ARRAY_SIZE(grh_table),
311  &header->grh, buf + len);
312  len += IB_GRH_BYTES;
313  }
314 
315  ib_pack(bth_table, ARRAY_SIZE(bth_table),
316  &header->bth, buf + len);
317  len += IB_BTH_BYTES;
318 
319  ib_pack(deth_table, ARRAY_SIZE(deth_table),
320  &header->deth, buf + len);
321  len += IB_DETH_BYTES;
322 
323  if (header->immediate_present) {
324  memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data);
325  len += sizeof header->immediate_data;
326  }
327 
328  return len;
329 }
331 
341  struct ib_ud_header *header)
342 {
343  ib_unpack(lrh_table, ARRAY_SIZE(lrh_table),
344  buf, &header->lrh);
345  buf += IB_LRH_BYTES;
346 
347  if (header->lrh.link_version != 0) {
348  printk(KERN_WARNING "Invalid LRH.link_version %d\n",
349  header->lrh.link_version);
350  return -EINVAL;
351  }
352 
353  switch (header->lrh.link_next_header) {
354  case IB_LNH_IBA_LOCAL:
355  header->grh_present = 0;
356  break;
357 
358  case IB_LNH_IBA_GLOBAL:
359  header->grh_present = 1;
360  ib_unpack(grh_table, ARRAY_SIZE(grh_table),
361  buf, &header->grh);
362  buf += IB_GRH_BYTES;
363 
364  if (header->grh.ip_version != 6) {
365  printk(KERN_WARNING "Invalid GRH.ip_version %d\n",
366  header->grh.ip_version);
367  return -EINVAL;
368  }
369  if (header->grh.next_header != 0x1b) {
370  printk(KERN_WARNING "Invalid GRH.next_header 0x%02x\n",
371  header->grh.next_header);
372  return -EINVAL;
373  }
374  break;
375 
376  default:
377  printk(KERN_WARNING "Invalid LRH.link_next_header %d\n",
378  header->lrh.link_next_header);
379  return -EINVAL;
380  }
381 
382  ib_unpack(bth_table, ARRAY_SIZE(bth_table),
383  buf, &header->bth);
384  buf += IB_BTH_BYTES;
385 
386  switch (header->bth.opcode) {
387  case IB_OPCODE_UD_SEND_ONLY:
388  header->immediate_present = 0;
389  break;
390  case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE:
391  header->immediate_present = 1;
392  break;
393  default:
394  printk(KERN_WARNING "Invalid BTH.opcode 0x%02x\n",
395  header->bth.opcode);
396  return -EINVAL;
397  }
398 
399  if (header->bth.transport_header_version != 0) {
400  printk(KERN_WARNING "Invalid BTH.transport_header_version %d\n",
401  header->bth.transport_header_version);
402  return -EINVAL;
403  }
404 
405  ib_unpack(deth_table, ARRAY_SIZE(deth_table),
406  buf, &header->deth);
407  buf += IB_DETH_BYTES;
408 
409  if (header->immediate_present)
410  memcpy(&header->immediate_data, buf, sizeof header->immediate_data);
411 
412  return 0;
413 }