1/*- 2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0 3 * 4 * Copyright (c) 2004 Topspin Corporation. All rights reserved. 5 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 6 * 7 * This software is available to you under a choice of one of two 8 * licenses. You may choose to be licensed under the terms of the GNU 9 * General Public License (GPL) Version 2, available from the file 10 * COPYING in the main directory of this source tree, or the 11 * OpenIB.org BSD license below: 12 * 13 * Redistribution and use in source and binary forms, with or 14 * without modification, are permitted provided that the following 15 * conditions are met: 16 * 17 * - Redistributions of source code must retain the above 18 * copyright notice, this list of conditions and the following 19 * disclaimer. 20 * 21 * - Redistributions in binary form must reproduce the above 22 * copyright notice, this list of conditions and the following 23 * disclaimer in the documentation and/or other materials 24 * provided with the distribution. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 * SOFTWARE. 34 */ 35 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD: stable/11/sys/ofed/drivers/infiniband/core/ib_ud_header.c 337096 2018-08-02 08:33:51Z hselasky $"); 38 39#include <linux/errno.h> 40#include <linux/string.h> 41#include <linux/if_ether.h> 42 43#include <rdma/ib_pack.h> 44 45#include <machine/in_cksum.h> 46 47#define STRUCT_FIELD(header, field) \ 48 .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \ 49 .struct_size_bytes = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \ 50 .field_name = #header ":" #field 51 52static const struct ib_field lrh_table[] = { 53 { STRUCT_FIELD(lrh, virtual_lane), 54 .offset_words = 0, 55 .offset_bits = 0, 56 .size_bits = 4 }, 57 { STRUCT_FIELD(lrh, link_version), 58 .offset_words = 0, 59 .offset_bits = 4, 60 .size_bits = 4 }, 61 { STRUCT_FIELD(lrh, service_level), 62 .offset_words = 0, 63 .offset_bits = 8, 64 .size_bits = 4 }, 65 { RESERVED, 66 .offset_words = 0, 67 .offset_bits = 12, 68 .size_bits = 2 }, 69 { STRUCT_FIELD(lrh, link_next_header), 70 .offset_words = 0, 71 .offset_bits = 14, 72 .size_bits = 2 }, 73 { STRUCT_FIELD(lrh, destination_lid), 74 .offset_words = 0, 75 .offset_bits = 16, 76 .size_bits = 16 }, 77 { RESERVED, 78 .offset_words = 1, 79 .offset_bits = 0, 80 .size_bits = 5 }, 81 { STRUCT_FIELD(lrh, packet_length), 82 .offset_words = 1, 83 .offset_bits = 5, 84 .size_bits = 11 }, 85 { STRUCT_FIELD(lrh, source_lid), 86 .offset_words = 1, 87 .offset_bits = 16, 88 .size_bits = 16 } 89}; 90 91static const struct ib_field eth_table[] = { 92 { STRUCT_FIELD(eth, dmac_h), 93 .offset_words = 0, 94 .offset_bits = 0, 95 .size_bits = 32 }, 96 { STRUCT_FIELD(eth, dmac_l), 97 .offset_words = 1, 98 .offset_bits = 0, 99 .size_bits = 16 }, 100 { STRUCT_FIELD(eth, smac_h), 101 .offset_words = 1, 102 .offset_bits = 16, 103 .size_bits = 16 }, 104 { STRUCT_FIELD(eth, smac_l), 105 .offset_words = 2, 106 .offset_bits = 0, 107 .size_bits = 32 }, 108 { STRUCT_FIELD(eth, type), 109 .offset_words = 3, 110 .offset_bits = 0, 111 .size_bits = 16 } 112}; 113 114static const struct ib_field vlan_table[] = { 115 { STRUCT_FIELD(vlan, tag), 116 .offset_words = 0, 117 .offset_bits = 0, 118 .size_bits = 16 }, 119 { STRUCT_FIELD(vlan, type), 120 .offset_words = 0, 121 .offset_bits = 16, 122 .size_bits = 16 } 123}; 124 125static const struct ib_field ip4_table[] = { 126 { STRUCT_FIELD(ip4, ver), 127 .offset_words = 0, 128 .offset_bits = 0, 129 .size_bits = 4 }, 130 { STRUCT_FIELD(ip4, hdr_len), 131 .offset_words = 0, 132 .offset_bits = 4, 133 .size_bits = 4 }, 134 { STRUCT_FIELD(ip4, tos), 135 .offset_words = 0, 136 .offset_bits = 8, 137 .size_bits = 8 }, 138 { STRUCT_FIELD(ip4, tot_len), 139 .offset_words = 0, 140 .offset_bits = 16, 141 .size_bits = 16 }, 142 { STRUCT_FIELD(ip4, id), 143 .offset_words = 1, 144 .offset_bits = 0, 145 .size_bits = 16 }, 146 { STRUCT_FIELD(ip4, frag_off), 147 .offset_words = 1, 148 .offset_bits = 16, 149 .size_bits = 16 }, 150 { STRUCT_FIELD(ip4, ttl), 151 .offset_words = 2, 152 .offset_bits = 0, 153 .size_bits = 8 }, 154 { STRUCT_FIELD(ip4, protocol), 155 .offset_words = 2, 156 .offset_bits = 8, 157 .size_bits = 8 }, 158 { STRUCT_FIELD(ip4, check), 159 .offset_words = 2, 160 .offset_bits = 16, 161 .size_bits = 16 }, 162 { STRUCT_FIELD(ip4, saddr), 163 .offset_words = 3, 164 .offset_bits = 0, 165 .size_bits = 32 }, 166 { STRUCT_FIELD(ip4, daddr), 167 .offset_words = 4, 168 .offset_bits = 0, 169 .size_bits = 32 } 170}; 171 172static const struct ib_field udp_table[] = { 173 { STRUCT_FIELD(udp, sport), 174 .offset_words = 0, 175 .offset_bits = 0, 176 .size_bits = 16 }, 177 { STRUCT_FIELD(udp, dport), 178 .offset_words = 0, 179 .offset_bits = 16, 180 .size_bits = 16 }, 181 { STRUCT_FIELD(udp, length), 182 .offset_words = 1, 183 .offset_bits = 0, 184 .size_bits = 16 }, 185 { STRUCT_FIELD(udp, csum), 186 .offset_words = 1, 187 .offset_bits = 16, 188 .size_bits = 16 } 189}; 190 191static const struct ib_field grh_table[] = { 192 { STRUCT_FIELD(grh, ip_version), 193 .offset_words = 0, 194 .offset_bits = 0, 195 .size_bits = 4 }, 196 { STRUCT_FIELD(grh, traffic_class), 197 .offset_words = 0, 198 .offset_bits = 4, 199 .size_bits = 8 }, 200 { STRUCT_FIELD(grh, flow_label), 201 .offset_words = 0, 202 .offset_bits = 12, 203 .size_bits = 20 }, 204 { STRUCT_FIELD(grh, payload_length), 205 .offset_words = 1, 206 .offset_bits = 0, 207 .size_bits = 16 }, 208 { STRUCT_FIELD(grh, next_header), 209 .offset_words = 1, 210 .offset_bits = 16, 211 .size_bits = 8 }, 212 { STRUCT_FIELD(grh, hop_limit), 213 .offset_words = 1, 214 .offset_bits = 24, 215 .size_bits = 8 }, 216 { STRUCT_FIELD(grh, source_gid), 217 .offset_words = 2, 218 .offset_bits = 0, 219 .size_bits = 128 }, 220 { STRUCT_FIELD(grh, destination_gid), 221 .offset_words = 6, 222 .offset_bits = 0, 223 .size_bits = 128 } 224}; 225 226static const struct ib_field bth_table[] = { 227 { STRUCT_FIELD(bth, opcode), 228 .offset_words = 0, 229 .offset_bits = 0, 230 .size_bits = 8 }, 231 { STRUCT_FIELD(bth, solicited_event), 232 .offset_words = 0, 233 .offset_bits = 8, 234 .size_bits = 1 }, 235 { STRUCT_FIELD(bth, mig_req), 236 .offset_words = 0, 237 .offset_bits = 9, 238 .size_bits = 1 }, 239 { STRUCT_FIELD(bth, pad_count), 240 .offset_words = 0, 241 .offset_bits = 10, 242 .size_bits = 2 }, 243 { STRUCT_FIELD(bth, transport_header_version), 244 .offset_words = 0, 245 .offset_bits = 12, 246 .size_bits = 4 }, 247 { STRUCT_FIELD(bth, pkey), 248 .offset_words = 0, 249 .offset_bits = 16, 250 .size_bits = 16 }, 251 { RESERVED, 252 .offset_words = 1, 253 .offset_bits = 0, 254 .size_bits = 8 }, 255 { STRUCT_FIELD(bth, destination_qpn), 256 .offset_words = 1, 257 .offset_bits = 8, 258 .size_bits = 24 }, 259 { STRUCT_FIELD(bth, ack_req), 260 .offset_words = 2, 261 .offset_bits = 0, 262 .size_bits = 1 }, 263 { RESERVED, 264 .offset_words = 2, 265 .offset_bits = 1, 266 .size_bits = 7 }, 267 { STRUCT_FIELD(bth, psn), 268 .offset_words = 2, 269 .offset_bits = 8, 270 .size_bits = 24 } 271}; 272 273static const struct ib_field deth_table[] = { 274 { STRUCT_FIELD(deth, qkey), 275 .offset_words = 0, 276 .offset_bits = 0, 277 .size_bits = 32 }, 278 { RESERVED, 279 .offset_words = 1, 280 .offset_bits = 0, 281 .size_bits = 8 }, 282 { STRUCT_FIELD(deth, source_qpn), 283 .offset_words = 1, 284 .offset_bits = 8, 285 .size_bits = 24 } 286}; 287 288__sum16 ib_ud_ip4_csum(struct ib_ud_header *header) 289{ 290#if defined(INET) || defined(INET6) 291 struct ip iph; 292 293 iph.ip_hl = 5; 294 iph.ip_v = 4; 295 iph.ip_tos = header->ip4.tos; 296 iph.ip_len = header->ip4.tot_len; 297 iph.ip_id = header->ip4.id; 298 iph.ip_off = header->ip4.frag_off; 299 iph.ip_ttl = header->ip4.ttl; 300 iph.ip_p = header->ip4.protocol; 301 iph.ip_sum = 0; 302 iph.ip_src.s_addr = header->ip4.saddr; 303 iph.ip_dst.s_addr = header->ip4.daddr; 304 305 return in_cksum_hdr(&iph); 306#else 307 return 0; 308#endif 309} 310EXPORT_SYMBOL(ib_ud_ip4_csum); 311 312/** 313 * ib_ud_header_init - Initialize UD header structure 314 * @payload_bytes:Length of packet payload 315 * @lrh_present: specify if LRH is present 316 * @eth_present: specify if Eth header is present 317 * @vlan_present: packet is tagged vlan 318 * @grh_present: GRH flag (if non-zero, GRH will be included) 319 * @ip_version: if non-zero, IP header, V4 or V6, will be included 320 * @udp_present :if non-zero, UDP header will be included 321 * @immediate_present: specify if immediate data is present 322 * @header:Structure to initialize 323 */ 324int ib_ud_header_init(int payload_bytes, 325 int lrh_present, 326 int eth_present, 327 int vlan_present, 328 int grh_present, 329 int ip_version, 330 int udp_present, 331 int immediate_present, 332 struct ib_ud_header *header) 333{ 334 size_t udp_bytes = udp_present ? IB_UDP_BYTES : 0; 335 336 grh_present = grh_present && !ip_version; 337 memset(header, 0, sizeof *header); 338 339 /* 340 * UDP header without IP header doesn't make sense 341 */ 342 if (udp_present && ip_version != 4 && ip_version != 6) 343 return -EINVAL; 344 345 if (lrh_present) { 346 u16 packet_length; 347 348 header->lrh.link_version = 0; 349 header->lrh.link_next_header = 350 grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL; 351 packet_length = (IB_LRH_BYTES + 352 IB_BTH_BYTES + 353 IB_DETH_BYTES + 354 (grh_present ? IB_GRH_BYTES : 0) + 355 payload_bytes + 356 4 + /* ICRC */ 357 3) / 4; /* round up */ 358 header->lrh.packet_length = cpu_to_be16(packet_length); 359 } 360 361 if (vlan_present) 362 header->eth.type = cpu_to_be16(ETH_P_8021Q); 363 364 if (ip_version == 6 || grh_present) { 365 header->grh.ip_version = 6; 366 header->grh.payload_length = 367 cpu_to_be16((udp_bytes + 368 IB_BTH_BYTES + 369 IB_DETH_BYTES + 370 payload_bytes + 371 4 + /* ICRC */ 372 3) & ~3); /* round up */ 373 header->grh.next_header = udp_present ? IPPROTO_UDP : 0x1b; 374 } 375 376 if (ip_version == 4) { 377 header->ip4.ver = 4; /* version 4 */ 378 header->ip4.hdr_len = 5; /* 5 words */ 379 header->ip4.tot_len = 380 cpu_to_be16(IB_IP4_BYTES + 381 udp_bytes + 382 IB_BTH_BYTES + 383 IB_DETH_BYTES + 384 payload_bytes + 385 4); /* ICRC */ 386 header->ip4.protocol = IPPROTO_UDP; 387 } 388 if (udp_present && ip_version) 389 header->udp.length = 390 cpu_to_be16(IB_UDP_BYTES + 391 IB_BTH_BYTES + 392 IB_DETH_BYTES + 393 payload_bytes + 394 4); /* ICRC */ 395 396 if (immediate_present) 397 header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; 398 else 399 header->bth.opcode = IB_OPCODE_UD_SEND_ONLY; 400 header->bth.pad_count = (4 - payload_bytes) & 3; 401 header->bth.transport_header_version = 0; 402 403 header->lrh_present = lrh_present; 404 header->eth_present = eth_present; 405 header->vlan_present = vlan_present; 406 header->grh_present = grh_present || (ip_version == 6); 407 header->ipv4_present = ip_version == 4; 408 header->udp_present = udp_present; 409 header->immediate_present = immediate_present; 410 return 0; 411} 412EXPORT_SYMBOL(ib_ud_header_init); 413 414/** 415 * ib_ud_header_pack - Pack UD header struct into wire format 416 * @header:UD header struct 417 * @buf:Buffer to pack into 418 * 419 * ib_ud_header_pack() packs the UD header structure @header into wire 420 * format in the buffer @buf. 421 */ 422int ib_ud_header_pack(struct ib_ud_header *header, 423 void *buf) 424{ 425 int len = 0; 426 427 if (header->lrh_present) { 428 ib_pack(lrh_table, ARRAY_SIZE(lrh_table), 429 &header->lrh, (char *)buf + len); 430 len += IB_LRH_BYTES; 431 } 432 if (header->eth_present) { 433 ib_pack(eth_table, ARRAY_SIZE(eth_table), 434 &header->eth, (char *)buf + len); 435 len += IB_ETH_BYTES; 436 } 437 if (header->vlan_present) { 438 ib_pack(vlan_table, ARRAY_SIZE(vlan_table), 439 &header->vlan, (char *)buf + len); 440 len += IB_VLAN_BYTES; 441 } 442 if (header->grh_present) { 443 ib_pack(grh_table, ARRAY_SIZE(grh_table), 444 &header->grh, (char *)buf + len); 445 len += IB_GRH_BYTES; 446 } 447 if (header->ipv4_present) { 448 ib_pack(ip4_table, ARRAY_SIZE(ip4_table), 449 &header->ip4, (char *)buf + len); 450 len += IB_IP4_BYTES; 451 } 452 if (header->udp_present) { 453 ib_pack(udp_table, ARRAY_SIZE(udp_table), 454 &header->udp, (char *)buf + len); 455 len += IB_UDP_BYTES; 456 } 457 458 ib_pack(bth_table, ARRAY_SIZE(bth_table), 459 &header->bth, (char *)buf + len); 460 len += IB_BTH_BYTES; 461 462 ib_pack(deth_table, ARRAY_SIZE(deth_table), 463 &header->deth, (char *)buf + len); 464 len += IB_DETH_BYTES; 465 466 if (header->immediate_present) { 467 memcpy((char *)buf + len, &header->immediate_data, sizeof header->immediate_data); 468 len += sizeof header->immediate_data; 469 } 470 471 return len; 472} 473EXPORT_SYMBOL(ib_ud_header_pack); 474 475/** 476 * ib_ud_header_unpack - Unpack UD header struct from wire format 477 * @header:UD header struct 478 * @buf:Buffer to pack into 479 * 480 * ib_ud_header_pack() unpacks the UD header structure @header from wire 481 * format in the buffer @buf. 482 */ 483int ib_ud_header_unpack(void *buf, 484 struct ib_ud_header *header) 485{ 486 ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), 487 buf, &header->lrh); 488 buf = (char *)buf + IB_LRH_BYTES; 489 490 if (header->lrh.link_version != 0) { 491 pr_warn("Invalid LRH.link_version %d\n", 492 header->lrh.link_version); 493 return -EINVAL; 494 } 495 496 switch (header->lrh.link_next_header) { 497 case IB_LNH_IBA_LOCAL: 498 header->grh_present = 0; 499 break; 500 501 case IB_LNH_IBA_GLOBAL: 502 header->grh_present = 1; 503 ib_unpack(grh_table, ARRAY_SIZE(grh_table), 504 buf, &header->grh); 505 buf = (char *)buf + IB_GRH_BYTES; 506 507 if (header->grh.ip_version != 6) { 508 pr_warn("Invalid GRH.ip_version %d\n", 509 header->grh.ip_version); 510 return -EINVAL; 511 } 512 if (header->grh.next_header != 0x1b) { 513 pr_warn("Invalid GRH.next_header 0x%02x\n", 514 header->grh.next_header); 515 return -EINVAL; 516 } 517 break; 518 519 default: 520 pr_warn("Invalid LRH.link_next_header %d\n", 521 header->lrh.link_next_header); 522 return -EINVAL; 523 } 524 525 ib_unpack(bth_table, ARRAY_SIZE(bth_table), 526 buf, &header->bth); 527 buf = (char *)buf + IB_BTH_BYTES; 528 529 switch (header->bth.opcode) { 530 case IB_OPCODE_UD_SEND_ONLY: 531 header->immediate_present = 0; 532 break; 533 case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE: 534 header->immediate_present = 1; 535 break; 536 default: 537 pr_warn("Invalid BTH.opcode 0x%02x\n", header->bth.opcode); 538 return -EINVAL; 539 } 540 541 if (header->bth.transport_header_version != 0) { 542 pr_warn("Invalid BTH.transport_header_version %d\n", 543 header->bth.transport_header_version); 544 return -EINVAL; 545 } 546 547 ib_unpack(deth_table, ARRAY_SIZE(deth_table), 548 buf, &header->deth); 549 buf = (char *)buf + IB_DETH_BYTES; 550 551 if (header->immediate_present) 552 memcpy(&header->immediate_data, buf, sizeof header->immediate_data); 553 554 return 0; 555} 556EXPORT_SYMBOL(ib_ud_header_unpack); 557