1 /*
   2  * Copyright (c) 2008-2015 Solarflare Communications Inc.
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions are met:
   7  *
   8  * 1. Redistributions of source code must retain the above copyright notice,
   9  *    this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright notice,
  11  *    this list of conditions and the following disclaimer in the documentation
  12  *    and/or other materials provided with the distribution.
  13  *
  14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25  *
  26  * The views and conclusions contained in the software and documentation are
  27  * those of the authors and should not be interpreted as representing official
  28  * policies, either expressed or implied, of the FreeBSD Project.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/sysmacros.h>
  33 #include <sys/ddi.h>
  34 #include <sys/sunddi.h>
  35 #include <sys/stream.h>
  36 #include <sys/strsun.h>
  37 #include <sys/strsubr.h>
  38 #include <sys/pattr.h>
  39 
  40 #include <sys/ethernet.h>
  41 #include <inet/ip.h>
  42 
  43 #include <netinet/in.h>
  44 #include <netinet/ip.h>
  45 #include <netinet/tcp.h>
  46 #include <netinet/udp.h>
  47 #include <netinet/sctp.h>
  48 
  49 #include "sfxge.h"
  50 
  51 #include "efx.h"
  52 
  53 
  54 /*
  55  * Parse packet headers and return:
  56  *      etherhpp        Ethernet MAC header
  57  *      iphpp           IPv4 header (NULL for non-IPv4 packet)
  58  *      thpp            TCP header (NULL for non-TCP packet)
  59  *      offp            Offset to TCP payload
  60  *      sizep           Size of TCP payload
  61  *      dportp          TCP/UDP/SCTP dest. port (network order), otherwise zero
  62  *      sportp          TCP/UDP/SCTP source port, (network order) otherwise zero
  63  */
  64 sfxge_packet_type_t
  65 sfxge_pkthdr_parse(mblk_t *mp, struct ether_header **etherhpp,
  66     struct ip **iphpp, struct tcphdr **thpp,
  67     size_t *offp, size_t *sizep,
  68     uint16_t *sportp, uint16_t *dportp)
  69 {
  70         struct ether_header *etherhp;
  71         uint16_t ether_type;
  72         size_t etherhs;
  73         struct ip *iphp;
  74         size_t iphs;
  75         struct tcphdr *thp;
  76         size_t len;
  77         size_t ths;
  78         size_t off;
  79         size_t size;
  80         uint16_t sport;
  81         uint16_t dport;
  82         sfxge_packet_type_t pkt_type = SFXGE_PACKET_TYPE_UNKNOWN;
  83 
  84         etherhp = NULL;
  85         iphp = NULL;
  86         thp = NULL;
  87         off = 0;
  88         size = 0;
  89         sport = 0;
  90         dport = 0;
  91 
  92         /* Grab the MAC header */
  93         etherhs = sizeof (struct ether_header);
  94         if ((MBLKL(mp) < etherhs) && (pullupmsg(mp, etherhs) == 0))
  95                 goto done;
  96 
  97         /*LINTED*/
  98         etherhp = (struct ether_header *)(mp->b_rptr);
  99         ether_type = etherhp->ether_type;
 100 
 101         if (ether_type == htons(ETHERTYPE_VLAN)) {
 102                 struct ether_vlan_header *ethervhp;
 103 
 104                 etherhs = sizeof (struct ether_vlan_header);
 105                 if ((MBLKL(mp) < etherhs) && (pullupmsg(mp, etherhs) == 0))
 106                         goto done;
 107 
 108                 /*LINTED*/
 109                 ethervhp = (struct ether_vlan_header *)(mp->b_rptr);
 110                 ether_type = ethervhp->ether_type;
 111         }
 112 
 113         if (ether_type != htons(ETHERTYPE_IP))
 114                 goto done;
 115 
 116         /* Skip over the MAC header */
 117         off += etherhs;
 118 
 119         /* Grab the IP header */
 120         len = off + sizeof (struct ip);
 121         if ((MBLKL(mp) < len) && (pullupmsg(mp, len) == 0))
 122                 goto done;
 123 
 124         /*LINTED*/
 125         iphp = (struct ip *)(mp->b_rptr + off);
 126         iphs = iphp->ip_hl * 4;
 127 
 128         if (iphp->ip_v != IPV4_VERSION)
 129                 goto done;
 130 
 131         /* Get the size of the packet */
 132         size = ntohs(iphp->ip_len);
 133 
 134         ASSERT3U(etherhs + size, <=, msgdsize(mp));
 135 
 136         pkt_type = SFXGE_PACKET_TYPE_IPV4_OTHER;
 137 
 138         /* Skip over the IP header */
 139         off += iphs;
 140         size -= iphs;
 141 
 142         if (iphp->ip_p == IPPROTO_TCP) {
 143                 /* Grab the TCP header */
 144                 len = off + sizeof (struct tcphdr);
 145                 if ((MBLKL(mp) < len) && (pullupmsg(mp, len) == 0))
 146                         goto done;
 147 
 148                 /*LINTED*/
 149                 thp = (struct tcphdr *)(mp->b_rptr + off);
 150                 ths = thp->th_off * 4;
 151 
 152                 dport = thp->th_dport;
 153                 sport = thp->th_sport;
 154 
 155                 /* Skip over the TCP header */
 156                 off += ths;
 157                 size -= ths;
 158 
 159                 pkt_type = SFXGE_PACKET_TYPE_IPV4_TCP;
 160 
 161         } else if (iphp->ip_p == IPPROTO_UDP) {
 162                 struct udphdr *uhp;
 163 
 164                 /* Grab the UDP header */
 165                 len = off + sizeof (struct udphdr);
 166                 if ((MBLKL(mp) < len) && (pullupmsg(mp, len) == 0))
 167                         goto done;
 168 
 169                 /*LINTED*/
 170                 uhp = (struct udphdr *)(mp->b_rptr + off);
 171                 dport = uhp->uh_dport;
 172                 sport = uhp->uh_sport;
 173 
 174                 /* Skip over the UDP header */
 175                 off += sizeof (struct udphdr);
 176                 size -= sizeof (struct udphdr);
 177 
 178                 pkt_type = SFXGE_PACKET_TYPE_IPV4_UDP;
 179 
 180         } else if (iphp->ip_p == IPPROTO_SCTP) {
 181                 struct sctp_hdr *shp;
 182 
 183                 /* Grab the SCTP header */
 184                 len = off + sizeof (struct sctp_hdr);
 185                 if ((MBLKL(mp) < len) && (pullupmsg(mp, len) == 0))
 186                         goto done;
 187 
 188                 /*LINTED*/
 189                 shp = (struct sctp_hdr *)(mp->b_rptr + off);
 190                 dport = shp->sh_dport;
 191                 sport = shp->sh_sport;
 192 
 193                 /* Skip over the SCTP header */
 194                 off += sizeof (struct sctp_hdr);
 195                 size -= sizeof (struct sctp_hdr);
 196 
 197                 pkt_type = SFXGE_PACKET_TYPE_IPV4_SCTP;
 198         }
 199 
 200         if (MBLKL(mp) < off)
 201                 (void) pullupmsg(mp, off);
 202 
 203 done:
 204         *etherhpp = etherhp;
 205         *iphpp = iphp;
 206         *thpp = thp;
 207         *offp = off;
 208         *sizep = size;
 209         *sportp = sport;
 210         *dportp = dport;
 211 
 212         return (pkt_type);
 213 }