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