548 lines · c
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 two6 * licenses. You may choose to be licensed under the terms of the GNU7 * General Public License (GPL) Version 2, available from the file8 * COPYING in the main directory of this source tree, or the9 * OpenIB.org BSD license below:10 *11 * Redistribution and use in source and binary forms, with or12 * without modification, are permitted provided that the following13 * conditions are met:14 *15 * - Redistributions of source code must retain the above16 * copyright notice, this list of conditions and the following17 * disclaimer.18 *19 * - Redistributions in binary form must reproduce the above20 * copyright notice, this list of conditions and the following21 * disclaimer in the documentation and/or other materials22 * 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 OF26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE31 * 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 ":" #field46 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 structure305 * @payload_bytes:Length of packet payload306 * @lrh_present: specify if LRH is present307 * @eth_present: specify if Eth header is present308 * @vlan_present: packet is tagged vlan309 * @grh_present: GRH flag (if non-zero, GRH will be included)310 * @ip_version: if non-zero, IP header, V4 or V6, will be included311 * @udp_present :if non-zero, UDP header will be included312 * @immediate_present: specify if immediate data is present313 * @header:Structure to initialize314 */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 sense332 */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 else390 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 format407 * @header:UD header struct408 * @buf:Buffer to pack into409 *410 * ib_ud_header_pack() packs the UD header structure @header into wire411 * 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 format468 * @header:UD header struct469 * @buf:Buffer to pack into470 *471 * ib_ud_header_pack() unpacks the UD header structure @header from wire472 * 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);548