1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * DL_IPV4 MAC Type plugin for the Nemo mac module
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/modctl.h>
  32 #include <sys/dlpi.h>
  33 #include <sys/mac.h>
  34 #include <sys/mac_ipv4.h>
  35 #include <sys/byteorder.h>
  36 #include <sys/strsun.h>
  37 #include <netinet/in.h>
  38 #include <netinet/ip.h>
  39 #include <inet/common.h>
  40 #include <inet/ip.h>
  41 #include <inet/iptun.h>
  42 
  43 static struct modlmisc mac_ipv4_modlmisc = {
  44         &mod_miscops,
  45         "IPv4 tunneling MAC plugin"
  46 };
  47 
  48 static struct modlinkage mac_ipv4_modlinkage = {
  49         MODREV_1,
  50         &mac_ipv4_modlmisc,
  51         NULL
  52 };
  53 
  54 static mactype_ops_t mac_ipv4_type_ops;
  55 
  56 int
  57 _init(void)
  58 {
  59         mactype_register_t *mtrp;
  60         int     err;
  61 
  62         if ((mtrp = mactype_alloc(MACTYPE_VERSION)) == NULL)
  63                 return (ENOTSUP);
  64         mtrp->mtr_ident = MAC_PLUGIN_IDENT_IPV4;
  65         mtrp->mtr_ops = &mac_ipv4_type_ops;
  66         mtrp->mtr_mactype = DL_IPV4;
  67         mtrp->mtr_nativetype = DL_IPV4;
  68         mtrp->mtr_addrlen = sizeof (ipaddr_t);
  69         if ((err = mactype_register(mtrp)) == 0) {
  70                 if ((err = mod_install(&mac_ipv4_modlinkage)) != 0)
  71                         (void) mactype_unregister(MAC_PLUGIN_IDENT_IPV4);
  72         }
  73         mactype_free(mtrp);
  74         return (err);
  75 }
  76 
  77 int
  78 _fini(void)
  79 {
  80         int     err;
  81         if ((err = mactype_unregister(MAC_PLUGIN_IDENT_IPV4)) != 0)
  82                 return (err);
  83         return (mod_remove(&mac_ipv4_modlinkage));
  84 }
  85 
  86 int
  87 _info(struct modinfo *modinfop)
  88 {
  89         return (mod_info(&mac_ipv4_modlinkage, modinfop));
  90 }
  91 
  92 /*
  93  * MAC Type plugin operations
  94  */
  95 
  96 /* ARGSUSED */
  97 int
  98 mac_ipv4_unicst_verify(const void *addr, void *pdata)
  99 {
 100         const ipaddr_t *ipaddr = addr;
 101         return ((CLASSD(*ipaddr) || (*ipaddr == INADDR_BROADCAST)) ?
 102             EINVAL : 0);
 103 }
 104 
 105 /* ARGSUSED */
 106 int
 107 mac_ipv4_multicst_verify(const void *addr, void *pdata)
 108 {
 109         /*
 110          * IPv4 configured tunnels do not have the concept of link-layer
 111          * multicast.
 112          */
 113         return (ENOTSUP);
 114 }
 115 
 116 /*
 117  * Check the legality of an IPv4 tunnel SAP value.  The only two acceptable
 118  * values are IPPROTO_ENCAP (IPv4 in IPv4) and IPPROTO_IPV6 (IPv6 in IPv4).
 119  */
 120 /* ARGSUSED */
 121 boolean_t
 122 mac_ipv4_sap_verify(uint32_t sap, uint32_t *bind_sap, void *pdata)
 123 {
 124         if (sap == IPPROTO_ENCAP || sap == IPPROTO_IPV6 || sap == 0) {
 125                 if (bind_sap != NULL)
 126                         *bind_sap = sap;
 127                 return (B_TRUE);
 128         }
 129         return (B_FALSE);
 130 }
 131 
 132 /*
 133  * Build an IPv4 link-layer header for tunneling.  If provided, the
 134  * template header provided by the driver supplies the header length, type
 135  * of service, don't fragment flag, ttl, and potential options (depending
 136  * on the header length).
 137  */
 138 /* ARGSUSED */
 139 mblk_t *
 140 mac_ipv4_header(const void *saddr, const void *daddr, uint32_t sap, void *pdata,
 141     mblk_t *payload, size_t extra_len)
 142 {
 143         struct ip       *iphp;
 144         struct ip       *tmpl_iphp = pdata;
 145         mblk_t          *mp;
 146         size_t          hdr_len = sizeof (struct ip);
 147 
 148         if (!mac_ipv4_sap_verify(sap, NULL, NULL))
 149                 return (NULL);
 150 
 151         if (tmpl_iphp != NULL)
 152                 hdr_len = tmpl_iphp->ip_hl * sizeof (uint32_t);
 153 
 154         if ((mp = allocb(hdr_len + extra_len, BPRI_HI)) == NULL)
 155                 return (NULL);
 156 
 157         iphp = (struct ip *)mp->b_rptr;
 158 
 159         bzero(iphp, hdr_len + extra_len);
 160         if (tmpl_iphp != NULL) {
 161                 bcopy(tmpl_iphp, iphp, hdr_len);
 162         } else {
 163                 iphp->ip_hl = IP_SIMPLE_HDR_LENGTH_IN_WORDS;
 164                 iphp->ip_off = htons(IP_DF);
 165                 iphp->ip_ttl = IPTUN_DEFAULT_HOPLIMIT;
 166         }
 167 
 168         iphp->ip_v = IPVERSION;
 169         iphp->ip_len = 0;
 170         iphp->ip_p = (uint8_t)sap;
 171         bcopy(saddr, &(iphp->ip_src), sizeof (struct in_addr));
 172         bcopy(daddr, &(iphp->ip_dst), sizeof (struct in_addr));
 173 
 174         mp->b_wptr += hdr_len;
 175         return (mp);
 176 }
 177 
 178 /* ARGSUSED */
 179 int
 180 mac_ipv4_header_info(mblk_t *mp, void *pdata, mac_header_info_t *hdr_info)
 181 {
 182         struct ip       *iphp;
 183 
 184         if (MBLKL(mp) < sizeof (struct ip))
 185                 return (EINVAL);
 186 
 187         iphp = (struct ip *)mp->b_rptr;
 188 
 189         /*
 190          * IPv4 tunnels don't have a concept of link-layer multicast since
 191          * they have fixed unicast endpoints.
 192          */
 193         if (mac_ipv4_unicst_verify(&iphp->ip_dst, NULL) != 0)
 194                 return (EINVAL);
 195 
 196         hdr_info->mhi_hdrsize = iphp->ip_hl * sizeof (uint32_t);
 197         hdr_info->mhi_pktsize = 0;
 198         hdr_info->mhi_daddr = (const uint8_t *)&(iphp->ip_dst);
 199         hdr_info->mhi_saddr = (const uint8_t *)&(iphp->ip_src);
 200         hdr_info->mhi_origsap = hdr_info->mhi_bindsap = iphp->ip_p;
 201         hdr_info->mhi_dsttype = MAC_ADDRTYPE_UNICAST;
 202         return (0);
 203 }
 204 
 205 /*
 206  * Plugin data is either NULL or a pointer to an IPv4 header.
 207  */
 208 boolean_t
 209 mac_ipv4_pdata_verify(void *pdata, size_t pdata_size)
 210 {
 211         const struct ip *iphp = pdata;
 212 
 213         if (pdata == NULL)
 214                 return (pdata_size == 0);
 215         if (pdata_size < sizeof (struct ip))
 216                 return (B_FALSE);
 217         /* Make sure that the header length field matches pdata_size */
 218         return (pdata_size == iphp->ip_hl * sizeof (uint32_t));
 219 }
 220 
 221 static mactype_ops_t    mac_ipv4_type_ops = {
 222         MTOPS_PDATA_VERIFY,
 223         mac_ipv4_unicst_verify,
 224         mac_ipv4_multicst_verify,
 225         mac_ipv4_sap_verify,
 226         mac_ipv4_header,
 227         mac_ipv4_header_info,
 228         mac_ipv4_pdata_verify,
 229         NULL,
 230         NULL,
 231         NULL
 232 };