Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
0003  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0004  *
0005  * This software is available to you under a choice of one of two
0006  * licenses.  You may choose to be licensed under the terms of the GNU
0007  * General Public License (GPL) Version 2, available from the file
0008  * COPYING in the main directory of this source tree, or the
0009  * OpenIB.org BSD license below:
0010  *
0011  *     Redistribution and use in source and binary forms, with or
0012  *     without modification, are permitted provided that the following
0013  *     conditions are met:
0014  *
0015  *      - Redistributions of source code must retain the above
0016  *        copyright notice, this list of conditions and the following
0017  *        disclaimer.
0018  *
0019  *      - Redistributions in binary form must reproduce the above
0020  *        copyright notice, this list of conditions and the following
0021  *        disclaimer in the documentation and/or other materials
0022  *        provided with the distribution.
0023  *
0024  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0025  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0026  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0027  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0028  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0029  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0030  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0031  * SOFTWARE.
0032  */
0033 
0034 #include <linux/errno.h>
0035 #include <linux/string.h>
0036 #include <linux/export.h>
0037 #include <linux/if_ether.h>
0038 #include <linux/ip.h>
0039 
0040 #include <rdma/ib_pack.h>
0041 
0042 #define STRUCT_FIELD(header, field) \
0043     .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field),      \
0044     .struct_size_bytes   = sizeof_field(struct ib_unpacked_ ## header, field), \
0045     .field_name          = #header ":" #field
0046 
0047 static const struct ib_field lrh_table[]  = {
0048     { STRUCT_FIELD(lrh, virtual_lane),
0049       .offset_words = 0,
0050       .offset_bits  = 0,
0051       .size_bits    = 4 },
0052     { STRUCT_FIELD(lrh, link_version),
0053       .offset_words = 0,
0054       .offset_bits  = 4,
0055       .size_bits    = 4 },
0056     { STRUCT_FIELD(lrh, service_level),
0057       .offset_words = 0,
0058       .offset_bits  = 8,
0059       .size_bits    = 4 },
0060     { RESERVED,
0061       .offset_words = 0,
0062       .offset_bits  = 12,
0063       .size_bits    = 2 },
0064     { STRUCT_FIELD(lrh, link_next_header),
0065       .offset_words = 0,
0066       .offset_bits  = 14,
0067       .size_bits    = 2 },
0068     { STRUCT_FIELD(lrh, destination_lid),
0069       .offset_words = 0,
0070       .offset_bits  = 16,
0071       .size_bits    = 16 },
0072     { RESERVED,
0073       .offset_words = 1,
0074       .offset_bits  = 0,
0075       .size_bits    = 5 },
0076     { STRUCT_FIELD(lrh, packet_length),
0077       .offset_words = 1,
0078       .offset_bits  = 5,
0079       .size_bits    = 11 },
0080     { STRUCT_FIELD(lrh, source_lid),
0081       .offset_words = 1,
0082       .offset_bits  = 16,
0083       .size_bits    = 16 }
0084 };
0085 
0086 static const struct ib_field eth_table[]  = {
0087     { STRUCT_FIELD(eth, dmac_h),
0088       .offset_words = 0,
0089       .offset_bits  = 0,
0090       .size_bits    = 32 },
0091     { STRUCT_FIELD(eth, dmac_l),
0092       .offset_words = 1,
0093       .offset_bits  = 0,
0094       .size_bits    = 16 },
0095     { STRUCT_FIELD(eth, smac_h),
0096       .offset_words = 1,
0097       .offset_bits  = 16,
0098       .size_bits    = 16 },
0099     { STRUCT_FIELD(eth, smac_l),
0100       .offset_words = 2,
0101       .offset_bits  = 0,
0102       .size_bits    = 32 },
0103     { STRUCT_FIELD(eth, type),
0104       .offset_words = 3,
0105       .offset_bits  = 0,
0106       .size_bits    = 16 }
0107 };
0108 
0109 static const struct ib_field vlan_table[]  = {
0110     { STRUCT_FIELD(vlan, tag),
0111       .offset_words = 0,
0112       .offset_bits  = 0,
0113       .size_bits    = 16 },
0114     { STRUCT_FIELD(vlan, type),
0115       .offset_words = 0,
0116       .offset_bits  = 16,
0117       .size_bits    = 16 }
0118 };
0119 
0120 static const struct ib_field ip4_table[]  = {
0121     { STRUCT_FIELD(ip4, ver),
0122       .offset_words = 0,
0123       .offset_bits  = 0,
0124       .size_bits    = 4 },
0125     { STRUCT_FIELD(ip4, hdr_len),
0126       .offset_words = 0,
0127       .offset_bits  = 4,
0128       .size_bits    = 4 },
0129     { STRUCT_FIELD(ip4, tos),
0130       .offset_words = 0,
0131       .offset_bits  = 8,
0132       .size_bits    = 8 },
0133     { STRUCT_FIELD(ip4, tot_len),
0134       .offset_words = 0,
0135       .offset_bits  = 16,
0136       .size_bits    = 16 },
0137     { STRUCT_FIELD(ip4, id),
0138       .offset_words = 1,
0139       .offset_bits  = 0,
0140       .size_bits    = 16 },
0141     { STRUCT_FIELD(ip4, frag_off),
0142       .offset_words = 1,
0143       .offset_bits  = 16,
0144       .size_bits    = 16 },
0145     { STRUCT_FIELD(ip4, ttl),
0146       .offset_words = 2,
0147       .offset_bits  = 0,
0148       .size_bits    = 8 },
0149     { STRUCT_FIELD(ip4, protocol),
0150       .offset_words = 2,
0151       .offset_bits  = 8,
0152       .size_bits    = 8 },
0153     { STRUCT_FIELD(ip4, check),
0154       .offset_words = 2,
0155       .offset_bits  = 16,
0156       .size_bits    = 16 },
0157     { STRUCT_FIELD(ip4, saddr),
0158       .offset_words = 3,
0159       .offset_bits  = 0,
0160       .size_bits    = 32 },
0161     { STRUCT_FIELD(ip4, daddr),
0162       .offset_words = 4,
0163       .offset_bits  = 0,
0164       .size_bits    = 32 }
0165 };
0166 
0167 static const struct ib_field udp_table[]  = {
0168     { STRUCT_FIELD(udp, sport),
0169       .offset_words = 0,
0170       .offset_bits  = 0,
0171       .size_bits    = 16 },
0172     { STRUCT_FIELD(udp, dport),
0173       .offset_words = 0,
0174       .offset_bits  = 16,
0175       .size_bits    = 16 },
0176     { STRUCT_FIELD(udp, length),
0177       .offset_words = 1,
0178       .offset_bits  = 0,
0179       .size_bits    = 16 },
0180     { STRUCT_FIELD(udp, csum),
0181       .offset_words = 1,
0182       .offset_bits  = 16,
0183       .size_bits    = 16 }
0184 };
0185 
0186 static const struct ib_field grh_table[]  = {
0187     { STRUCT_FIELD(grh, ip_version),
0188       .offset_words = 0,
0189       .offset_bits  = 0,
0190       .size_bits    = 4 },
0191     { STRUCT_FIELD(grh, traffic_class),
0192       .offset_words = 0,
0193       .offset_bits  = 4,
0194       .size_bits    = 8 },
0195     { STRUCT_FIELD(grh, flow_label),
0196       .offset_words = 0,
0197       .offset_bits  = 12,
0198       .size_bits    = 20 },
0199     { STRUCT_FIELD(grh, payload_length),
0200       .offset_words = 1,
0201       .offset_bits  = 0,
0202       .size_bits    = 16 },
0203     { STRUCT_FIELD(grh, next_header),
0204       .offset_words = 1,
0205       .offset_bits  = 16,
0206       .size_bits    = 8 },
0207     { STRUCT_FIELD(grh, hop_limit),
0208       .offset_words = 1,
0209       .offset_bits  = 24,
0210       .size_bits    = 8 },
0211     { STRUCT_FIELD(grh, source_gid),
0212       .offset_words = 2,
0213       .offset_bits  = 0,
0214       .size_bits    = 128 },
0215     { STRUCT_FIELD(grh, destination_gid),
0216       .offset_words = 6,
0217       .offset_bits  = 0,
0218       .size_bits    = 128 }
0219 };
0220 
0221 static const struct ib_field bth_table[]  = {
0222     { STRUCT_FIELD(bth, opcode),
0223       .offset_words = 0,
0224       .offset_bits  = 0,
0225       .size_bits    = 8 },
0226     { STRUCT_FIELD(bth, solicited_event),
0227       .offset_words = 0,
0228       .offset_bits  = 8,
0229       .size_bits    = 1 },
0230     { STRUCT_FIELD(bth, mig_req),
0231       .offset_words = 0,
0232       .offset_bits  = 9,
0233       .size_bits    = 1 },
0234     { STRUCT_FIELD(bth, pad_count),
0235       .offset_words = 0,
0236       .offset_bits  = 10,
0237       .size_bits    = 2 },
0238     { STRUCT_FIELD(bth, transport_header_version),
0239       .offset_words = 0,
0240       .offset_bits  = 12,
0241       .size_bits    = 4 },
0242     { STRUCT_FIELD(bth, pkey),
0243       .offset_words = 0,
0244       .offset_bits  = 16,
0245       .size_bits    = 16 },
0246     { RESERVED,
0247       .offset_words = 1,
0248       .offset_bits  = 0,
0249       .size_bits    = 8 },
0250     { STRUCT_FIELD(bth, destination_qpn),
0251       .offset_words = 1,
0252       .offset_bits  = 8,
0253       .size_bits    = 24 },
0254     { STRUCT_FIELD(bth, ack_req),
0255       .offset_words = 2,
0256       .offset_bits  = 0,
0257       .size_bits    = 1 },
0258     { RESERVED,
0259       .offset_words = 2,
0260       .offset_bits  = 1,
0261       .size_bits    = 7 },
0262     { STRUCT_FIELD(bth, psn),
0263       .offset_words = 2,
0264       .offset_bits  = 8,
0265       .size_bits    = 24 }
0266 };
0267 
0268 static const struct ib_field deth_table[] = {
0269     { STRUCT_FIELD(deth, qkey),
0270       .offset_words = 0,
0271       .offset_bits  = 0,
0272       .size_bits    = 32 },
0273     { RESERVED,
0274       .offset_words = 1,
0275       .offset_bits  = 0,
0276       .size_bits    = 8 },
0277     { STRUCT_FIELD(deth, source_qpn),
0278       .offset_words = 1,
0279       .offset_bits  = 8,
0280       .size_bits    = 24 }
0281 };
0282 
0283 __sum16 ib_ud_ip4_csum(struct ib_ud_header *header)
0284 {
0285     struct iphdr iph;
0286 
0287     iph.ihl     = 5;
0288     iph.version = 4;
0289     iph.tos     = header->ip4.tos;
0290     iph.tot_len = header->ip4.tot_len;
0291     iph.id      = header->ip4.id;
0292     iph.frag_off    = header->ip4.frag_off;
0293     iph.ttl     = header->ip4.ttl;
0294     iph.protocol    = header->ip4.protocol;
0295     iph.check   = 0;
0296     iph.saddr   = header->ip4.saddr;
0297     iph.daddr   = header->ip4.daddr;
0298 
0299     return ip_fast_csum((u8 *)&iph, iph.ihl);
0300 }
0301 EXPORT_SYMBOL(ib_ud_ip4_csum);
0302 
0303 /**
0304  * ib_ud_header_init - Initialize UD header structure
0305  * @payload_bytes:Length of packet payload
0306  * @lrh_present: specify if LRH is present
0307  * @eth_present: specify if Eth header is present
0308  * @vlan_present: packet is tagged vlan
0309  * @grh_present: GRH flag (if non-zero, GRH will be included)
0310  * @ip_version: if non-zero, IP header, V4 or V6, will be included
0311  * @udp_present :if non-zero, UDP header will be included
0312  * @immediate_present: specify if immediate data is present
0313  * @header:Structure to initialize
0314  */
0315 int ib_ud_header_init(int     payload_bytes,
0316               int    lrh_present,
0317               int    eth_present,
0318               int    vlan_present,
0319               int    grh_present,
0320               int    ip_version,
0321               int    udp_present,
0322               int    immediate_present,
0323               struct ib_ud_header *header)
0324 {
0325     size_t udp_bytes = udp_present ? IB_UDP_BYTES : 0;
0326 
0327     grh_present = grh_present && !ip_version;
0328     memset(header, 0, sizeof *header);
0329 
0330     /*
0331      * UDP header without IP header doesn't make sense
0332      */
0333     if (udp_present && ip_version != 4 && ip_version != 6)
0334         return -EINVAL;
0335 
0336     if (lrh_present) {
0337         u16 packet_length;
0338 
0339         header->lrh.link_version     = 0;
0340         header->lrh.link_next_header =
0341             grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
0342         packet_length = (IB_LRH_BYTES   +
0343                  IB_BTH_BYTES   +
0344                  IB_DETH_BYTES  +
0345                  (grh_present ? IB_GRH_BYTES : 0) +
0346                  payload_bytes  +
0347                  4      + /* ICRC     */
0348                  3) / 4;      /* round up */
0349         header->lrh.packet_length = cpu_to_be16(packet_length);
0350     }
0351 
0352     if (vlan_present)
0353         header->eth.type = cpu_to_be16(ETH_P_8021Q);
0354 
0355     if (ip_version == 6 || grh_present) {
0356         header->grh.ip_version      = 6;
0357         header->grh.payload_length  =
0358             cpu_to_be16((udp_bytes        +
0359                      IB_BTH_BYTES     +
0360                      IB_DETH_BYTES    +
0361                      payload_bytes    +
0362                      4                + /* ICRC     */
0363                      3) & ~3);          /* round up */
0364         header->grh.next_header     = udp_present ? IPPROTO_UDP : 0x1b;
0365     }
0366 
0367     if (ip_version == 4) {
0368         header->ip4.ver = 4; /* version 4 */
0369         header->ip4.hdr_len = 5; /* 5 words */
0370         header->ip4.tot_len =
0371             cpu_to_be16(IB_IP4_BYTES   +
0372                      udp_bytes     +
0373                      IB_BTH_BYTES  +
0374                      IB_DETH_BYTES +
0375                      payload_bytes +
0376                      4);     /* ICRC     */
0377         header->ip4.protocol = IPPROTO_UDP;
0378     }
0379     if (udp_present && ip_version)
0380         header->udp.length =
0381             cpu_to_be16(IB_UDP_BYTES   +
0382                      IB_BTH_BYTES  +
0383                      IB_DETH_BYTES +
0384                      payload_bytes +
0385                      4);     /* ICRC     */
0386 
0387     if (immediate_present)
0388         header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
0389     else
0390         header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY;
0391     header->bth.pad_count                = (4 - payload_bytes) & 3;
0392     header->bth.transport_header_version = 0;
0393 
0394     header->lrh_present = lrh_present;
0395     header->eth_present = eth_present;
0396     header->vlan_present = vlan_present;
0397     header->grh_present = grh_present || (ip_version == 6);
0398     header->ipv4_present = ip_version == 4;
0399     header->udp_present = udp_present;
0400     header->immediate_present = immediate_present;
0401     return 0;
0402 }
0403 EXPORT_SYMBOL(ib_ud_header_init);
0404 
0405 /**
0406  * ib_ud_header_pack - Pack UD header struct into wire format
0407  * @header:UD header struct
0408  * @buf:Buffer to pack into
0409  *
0410  * ib_ud_header_pack() packs the UD header structure @header into wire
0411  * format in the buffer @buf.
0412  */
0413 int ib_ud_header_pack(struct ib_ud_header *header,
0414               void                *buf)
0415 {
0416     int len = 0;
0417 
0418     if (header->lrh_present) {
0419         ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
0420             &header->lrh, buf + len);
0421         len += IB_LRH_BYTES;
0422     }
0423     if (header->eth_present) {
0424         ib_pack(eth_table, ARRAY_SIZE(eth_table),
0425             &header->eth, buf + len);
0426         len += IB_ETH_BYTES;
0427     }
0428     if (header->vlan_present) {
0429         ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
0430             &header->vlan, buf + len);
0431         len += IB_VLAN_BYTES;
0432     }
0433     if (header->grh_present) {
0434         ib_pack(grh_table, ARRAY_SIZE(grh_table),
0435             &header->grh, buf + len);
0436         len += IB_GRH_BYTES;
0437     }
0438     if (header->ipv4_present) {
0439         ib_pack(ip4_table, ARRAY_SIZE(ip4_table),
0440             &header->ip4, buf + len);
0441         len += IB_IP4_BYTES;
0442     }
0443     if (header->udp_present) {
0444         ib_pack(udp_table, ARRAY_SIZE(udp_table),
0445             &header->udp, buf + len);
0446         len += IB_UDP_BYTES;
0447     }
0448 
0449     ib_pack(bth_table, ARRAY_SIZE(bth_table),
0450         &header->bth, buf + len);
0451     len += IB_BTH_BYTES;
0452 
0453     ib_pack(deth_table, ARRAY_SIZE(deth_table),
0454         &header->deth, buf + len);
0455     len += IB_DETH_BYTES;
0456 
0457     if (header->immediate_present) {
0458         memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data);
0459         len += sizeof header->immediate_data;
0460     }
0461 
0462     return len;
0463 }
0464 EXPORT_SYMBOL(ib_ud_header_pack);
0465 
0466 /**
0467  * ib_ud_header_unpack - Unpack UD header struct from wire format
0468  * @header:UD header struct
0469  * @buf:Buffer to pack into
0470  *
0471  * ib_ud_header_pack() unpacks the UD header structure @header from wire
0472  * format in the buffer @buf.
0473  */
0474 int ib_ud_header_unpack(void                *buf,
0475             struct ib_ud_header *header)
0476 {
0477     ib_unpack(lrh_table, ARRAY_SIZE(lrh_table),
0478           buf, &header->lrh);
0479     buf += IB_LRH_BYTES;
0480 
0481     if (header->lrh.link_version != 0) {
0482         pr_warn("Invalid LRH.link_version %u\n",
0483             header->lrh.link_version);
0484         return -EINVAL;
0485     }
0486 
0487     switch (header->lrh.link_next_header) {
0488     case IB_LNH_IBA_LOCAL:
0489         header->grh_present = 0;
0490         break;
0491 
0492     case IB_LNH_IBA_GLOBAL:
0493         header->grh_present = 1;
0494         ib_unpack(grh_table, ARRAY_SIZE(grh_table),
0495               buf, &header->grh);
0496         buf += IB_GRH_BYTES;
0497 
0498         if (header->grh.ip_version != 6) {
0499             pr_warn("Invalid GRH.ip_version %u\n",
0500                 header->grh.ip_version);
0501             return -EINVAL;
0502         }
0503         if (header->grh.next_header != 0x1b) {
0504             pr_warn("Invalid GRH.next_header 0x%02x\n",
0505                 header->grh.next_header);
0506             return -EINVAL;
0507         }
0508         break;
0509 
0510     default:
0511         pr_warn("Invalid LRH.link_next_header %u\n",
0512             header->lrh.link_next_header);
0513         return -EINVAL;
0514     }
0515 
0516     ib_unpack(bth_table, ARRAY_SIZE(bth_table),
0517           buf, &header->bth);
0518     buf += IB_BTH_BYTES;
0519 
0520     switch (header->bth.opcode) {
0521     case IB_OPCODE_UD_SEND_ONLY:
0522         header->immediate_present = 0;
0523         break;
0524     case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE:
0525         header->immediate_present = 1;
0526         break;
0527     default:
0528         pr_warn("Invalid BTH.opcode 0x%02x\n", header->bth.opcode);
0529         return -EINVAL;
0530     }
0531 
0532     if (header->bth.transport_header_version != 0) {
0533         pr_warn("Invalid BTH.transport_header_version %u\n",
0534             header->bth.transport_header_version);
0535         return -EINVAL;
0536     }
0537 
0538     ib_unpack(deth_table, ARRAY_SIZE(deth_table),
0539           buf, &header->deth);
0540     buf += IB_DETH_BYTES;
0541 
0542     if (header->immediate_present)
0543         memcpy(&header->immediate_data, buf, sizeof header->immediate_data);
0544 
0545     return 0;
0546 }
0547 EXPORT_SYMBOL(ib_ud_header_unpack);