ib_ud_header.c revision 331769
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#include <machine/in_cksum.h> 41 42#define STRUCT_FIELD(header, field) \ 43 .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \ 44 .struct_size_bytes = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \ 45 .field_name = #header ":" #field 46 47static 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 86static 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 109static 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 120static 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 167static 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 186static 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 221static 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 268static 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 283__sum16 ib_ud_ip4_csum(struct ib_ud_header *header) 284{ 285#if defined(INET) || defined(INET6) 286 struct ip iph; 287 288 iph.ip_hl = 5; 289 iph.ip_v = 4; 290 iph.ip_tos = header->ip4.tos; 291 iph.ip_len = header->ip4.tot_len; 292 iph.ip_id = header->ip4.id; 293 iph.ip_off = header->ip4.frag_off; 294 iph.ip_ttl = header->ip4.ttl; 295 iph.ip_p = header->ip4.protocol; 296 iph.ip_sum = 0; 297 iph.ip_src.s_addr = header->ip4.saddr; 298 iph.ip_dst.s_addr = header->ip4.daddr; 299 300 return in_cksum_hdr(&iph); 301#else 302 return 0; 303#endif 304} 305EXPORT_SYMBOL(ib_ud_ip4_csum); 306 307/** 308 * ib_ud_header_init - Initialize UD header structure 309 * @payload_bytes:Length of packet payload 310 * @lrh_present: specify if LRH is present 311 * @eth_present: specify if Eth header is present 312 * @vlan_present: packet is tagged vlan 313 * @grh_present: GRH flag (if non-zero, GRH will be included) 314 * @ip_version: if non-zero, IP header, V4 or V6, will be included 315 * @udp_present :if non-zero, UDP header will be included 316 * @immediate_present: specify if immediate data is present 317 * @header:Structure to initialize 318 */ 319int ib_ud_header_init(int payload_bytes, 320 int lrh_present, 321 int eth_present, 322 int vlan_present, 323 int grh_present, 324 int ip_version, 325 int udp_present, 326 int immediate_present, 327 struct ib_ud_header *header) 328{ 329 size_t udp_bytes = udp_present ? IB_UDP_BYTES : 0; 330 331 grh_present = grh_present && !ip_version; 332 memset(header, 0, sizeof *header); 333 334 /* 335 * UDP header without IP header doesn't make sense 336 */ 337 if (udp_present && ip_version != 4 && ip_version != 6) 338 return -EINVAL; 339 340 if (lrh_present) { 341 u16 packet_length; 342 343 header->lrh.link_version = 0; 344 header->lrh.link_next_header = 345 grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL; 346 packet_length = (IB_LRH_BYTES + 347 IB_BTH_BYTES + 348 IB_DETH_BYTES + 349 (grh_present ? IB_GRH_BYTES : 0) + 350 payload_bytes + 351 4 + /* ICRC */ 352 3) / 4; /* round up */ 353 header->lrh.packet_length = cpu_to_be16(packet_length); 354 } 355 356 if (vlan_present) 357 header->eth.type = cpu_to_be16(ETH_P_8021Q); 358 359 if (ip_version == 6 || grh_present) { 360 header->grh.ip_version = 6; 361 header->grh.payload_length = 362 cpu_to_be16((udp_bytes + 363 IB_BTH_BYTES + 364 IB_DETH_BYTES + 365 payload_bytes + 366 4 + /* ICRC */ 367 3) & ~3); /* round up */ 368 header->grh.next_header = udp_present ? IPPROTO_UDP : 0x1b; 369 } 370 371 if (ip_version == 4) { 372 header->ip4.ver = 4; /* version 4 */ 373 header->ip4.hdr_len = 5; /* 5 words */ 374 header->ip4.tot_len = 375 cpu_to_be16(IB_IP4_BYTES + 376 udp_bytes + 377 IB_BTH_BYTES + 378 IB_DETH_BYTES + 379 payload_bytes + 380 4); /* ICRC */ 381 header->ip4.protocol = IPPROTO_UDP; 382 } 383 if (udp_present && ip_version) 384 header->udp.length = 385 cpu_to_be16(IB_UDP_BYTES + 386 IB_BTH_BYTES + 387 IB_DETH_BYTES + 388 payload_bytes + 389 4); /* ICRC */ 390 391 if (immediate_present) 392 header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; 393 else 394 header->bth.opcode = IB_OPCODE_UD_SEND_ONLY; 395 header->bth.pad_count = (4 - payload_bytes) & 3; 396 header->bth.transport_header_version = 0; 397 398 header->lrh_present = lrh_present; 399 header->eth_present = eth_present; 400 header->vlan_present = vlan_present; 401 header->grh_present = grh_present || (ip_version == 6); 402 header->ipv4_present = ip_version == 4; 403 header->udp_present = udp_present; 404 header->immediate_present = immediate_present; 405 return 0; 406} 407EXPORT_SYMBOL(ib_ud_header_init); 408 409/** 410 * ib_ud_header_pack - Pack UD header struct into wire format 411 * @header:UD header struct 412 * @buf:Buffer to pack into 413 * 414 * ib_ud_header_pack() packs the UD header structure @header into wire 415 * format in the buffer @buf. 416 */ 417int ib_ud_header_pack(struct ib_ud_header *header, 418 void *buf) 419{ 420 int len = 0; 421 422 if (header->lrh_present) { 423 ib_pack(lrh_table, ARRAY_SIZE(lrh_table), 424 &header->lrh, (char *)buf + len); 425 len += IB_LRH_BYTES; 426 } 427 if (header->eth_present) { 428 ib_pack(eth_table, ARRAY_SIZE(eth_table), 429 &header->eth, (char *)buf + len); 430 len += IB_ETH_BYTES; 431 } 432 if (header->vlan_present) { 433 ib_pack(vlan_table, ARRAY_SIZE(vlan_table), 434 &header->vlan, (char *)buf + len); 435 len += IB_VLAN_BYTES; 436 } 437 if (header->grh_present) { 438 ib_pack(grh_table, ARRAY_SIZE(grh_table), 439 &header->grh, (char *)buf + len); 440 len += IB_GRH_BYTES; 441 } 442 if (header->ipv4_present) { 443 ib_pack(ip4_table, ARRAY_SIZE(ip4_table), 444 &header->ip4, (char *)buf + len); 445 len += IB_IP4_BYTES; 446 } 447 if (header->udp_present) { 448 ib_pack(udp_table, ARRAY_SIZE(udp_table), 449 &header->udp, (char *)buf + len); 450 len += IB_UDP_BYTES; 451 } 452 453 ib_pack(bth_table, ARRAY_SIZE(bth_table), 454 &header->bth, (char *)buf + len); 455 len += IB_BTH_BYTES; 456 457 ib_pack(deth_table, ARRAY_SIZE(deth_table), 458 &header->deth, (char *)buf + len); 459 len += IB_DETH_BYTES; 460 461 if (header->immediate_present) { 462 memcpy((char *)buf + len, &header->immediate_data, sizeof header->immediate_data); 463 len += sizeof header->immediate_data; 464 } 465 466 return len; 467} 468EXPORT_SYMBOL(ib_ud_header_pack); 469 470/** 471 * ib_ud_header_unpack - Unpack UD header struct from wire format 472 * @header:UD header struct 473 * @buf:Buffer to pack into 474 * 475 * ib_ud_header_pack() unpacks the UD header structure @header from wire 476 * format in the buffer @buf. 477 */ 478int ib_ud_header_unpack(void *buf, 479 struct ib_ud_header *header) 480{ 481 ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), 482 buf, &header->lrh); 483 buf = (char *)buf + IB_LRH_BYTES; 484 485 if (header->lrh.link_version != 0) { 486 pr_warn("Invalid LRH.link_version %d\n", 487 header->lrh.link_version); 488 return -EINVAL; 489 } 490 491 switch (header->lrh.link_next_header) { 492 case IB_LNH_IBA_LOCAL: 493 header->grh_present = 0; 494 break; 495 496 case IB_LNH_IBA_GLOBAL: 497 header->grh_present = 1; 498 ib_unpack(grh_table, ARRAY_SIZE(grh_table), 499 buf, &header->grh); 500 buf = (char *)buf + IB_GRH_BYTES; 501 502 if (header->grh.ip_version != 6) { 503 pr_warn("Invalid GRH.ip_version %d\n", 504 header->grh.ip_version); 505 return -EINVAL; 506 } 507 if (header->grh.next_header != 0x1b) { 508 pr_warn("Invalid GRH.next_header 0x%02x\n", 509 header->grh.next_header); 510 return -EINVAL; 511 } 512 break; 513 514 default: 515 pr_warn("Invalid LRH.link_next_header %d\n", 516 header->lrh.link_next_header); 517 return -EINVAL; 518 } 519 520 ib_unpack(bth_table, ARRAY_SIZE(bth_table), 521 buf, &header->bth); 522 buf = (char *)buf + IB_BTH_BYTES; 523 524 switch (header->bth.opcode) { 525 case IB_OPCODE_UD_SEND_ONLY: 526 header->immediate_present = 0; 527 break; 528 case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE: 529 header->immediate_present = 1; 530 break; 531 default: 532 pr_warn("Invalid BTH.opcode 0x%02x\n", header->bth.opcode); 533 return -EINVAL; 534 } 535 536 if (header->bth.transport_header_version != 0) { 537 pr_warn("Invalid BTH.transport_header_version %d\n", 538 header->bth.transport_header_version); 539 return -EINVAL; 540 } 541 542 ib_unpack(deth_table, ARRAY_SIZE(deth_table), 543 buf, &header->deth); 544 buf = (char *)buf + IB_DETH_BYTES; 545 546 if (header->immediate_present) 547 memcpy(&header->immediate_data, buf, sizeof header->immediate_data); 548 549 return 0; 550} 551EXPORT_SYMBOL(ib_ud_header_unpack); 552