Print this page
    
First attempt at further IPsec cluster cleanup
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/inet/ip/ipsecah.c
          +++ new/usr/src/uts/common/inet/ip/ipsecah.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   *
  25   25   * Copyright 2015 Garrett D'Amore <garrett@damore.org>
  26   26   */
  27   27  
  28   28  #include <sys/types.h>
  29   29  #include <sys/stream.h>
  30   30  #include <sys/stropts.h>
  31   31  #include <sys/errno.h>
  32   32  #include <sys/strlog.h>
  33   33  #include <sys/tihdr.h>
  34   34  #include <sys/socket.h>
  35   35  #include <sys/ddi.h>
  36   36  #include <sys/sunddi.h>
  37   37  #include <sys/mkdev.h>
  38   38  #include <sys/kmem.h>
  39   39  #include <sys/zone.h>
  40   40  #include <sys/sysmacros.h>
  41   41  #include <sys/cmn_err.h>
  42   42  #include <sys/vtrace.h>
  43   43  #include <sys/debug.h>
  44   44  #include <sys/atomic.h>
  45   45  #include <sys/strsun.h>
  46   46  #include <sys/random.h>
  47   47  #include <netinet/in.h>
  48   48  #include <net/if.h>
  49   49  #include <netinet/ip6.h>
  50   50  #include <netinet/icmp6.h>
  51   51  #include <net/pfkeyv2.h>
  52   52  #include <net/pfpolicy.h>
  53   53  
  54   54  #include <inet/common.h>
  55   55  #include <inet/mi.h>
  56   56  #include <inet/ip.h>
  57   57  #include <inet/ip6.h>
  58   58  #include <inet/nd.h>
  59   59  #include <inet/ip_if.h>
  60   60  #include <inet/ip_ndp.h>
  61   61  #include <inet/ipsec_info.h>
  62   62  #include <inet/ipsec_impl.h>
  63   63  #include <inet/sadb.h>
  64   64  #include <inet/ipsecah.h>
  65   65  #include <inet/ipsec_impl.h>
  66   66  #include <inet/ipdrop.h>
  67   67  #include <sys/taskq.h>
  68   68  #include <sys/policy.h>
  69   69  #include <sys/strsun.h>
  70   70  
  71   71  #include <sys/crypto/common.h>
  72   72  #include <sys/crypto/api.h>
  73   73  #include <sys/kstat.h>
  74   74  #include <sys/strsubr.h>
  75   75  
  76   76  #include <sys/tsol/tnet.h>
  77   77  
  78   78  /*
  79   79   * Table of ND variables supported by ipsecah. These are loaded into
  80   80   * ipsecah_g_nd in ipsecah_init_nd.
  81   81   * All of these are alterable, within the min/max values given, at run time.
  82   82   */
  83   83  static  ipsecahparam_t  lcl_param_arr[] = {
  84   84          /* min  max                     value   name */
  85   85          { 0,    3,                      0,      "ipsecah_debug"},
  86   86          { 125,  32000, SADB_AGE_INTERVAL_DEFAULT,       "ipsecah_age_interval"},
  87   87          { 1,    10,                     1,      "ipsecah_reap_delay"},
  88   88          { 1,    SADB_MAX_REPLAY,        64,     "ipsecah_replay_size"},
  89   89          { 1,    300,                    15,     "ipsecah_acquire_timeout"},
  90   90          { 1,    1800,                   90,     "ipsecah_larval_timeout"},
  91   91          /* Default lifetime values for ACQUIRE messages. */
  92   92          { 0,    0xffffffffU,            0,      "ipsecah_default_soft_bytes"},
  93   93          { 0,    0xffffffffU,            0,      "ipsecah_default_hard_bytes"},
  94   94          { 0,    0xffffffffU,            24000,  "ipsecah_default_soft_addtime"},
  95   95          { 0,    0xffffffffU,            28800,  "ipsecah_default_hard_addtime"},
  96   96          { 0,    0xffffffffU,            0,      "ipsecah_default_soft_usetime"},
  97   97          { 0,    0xffffffffU,            0,      "ipsecah_default_hard_usetime"},
  98   98          { 0,    1,                      0,      "ipsecah_log_unknown_spi"},
  99   99  };
 100  100  #define ipsecah_debug                   ipsecah_params[0].ipsecah_param_value
 101  101  #define ipsecah_age_interval            ipsecah_params[1].ipsecah_param_value
 102  102  #define ipsecah_age_int_max             ipsecah_params[1].ipsecah_param_max
 103  103  #define ipsecah_reap_delay              ipsecah_params[2].ipsecah_param_value
 104  104  #define ipsecah_replay_size             ipsecah_params[3].ipsecah_param_value
 105  105  #define ipsecah_acquire_timeout         ipsecah_params[4].ipsecah_param_value
 106  106  #define ipsecah_larval_timeout          ipsecah_params[5].ipsecah_param_value
 107  107  #define ipsecah_default_soft_bytes      ipsecah_params[6].ipsecah_param_value
 108  108  #define ipsecah_default_hard_bytes      ipsecah_params[7].ipsecah_param_value
 109  109  #define ipsecah_default_soft_addtime    ipsecah_params[8].ipsecah_param_value
 110  110  #define ipsecah_default_hard_addtime    ipsecah_params[9].ipsecah_param_value
 111  111  #define ipsecah_default_soft_usetime    ipsecah_params[10].ipsecah_param_value
 112  112  #define ipsecah_default_hard_usetime    ipsecah_params[11].ipsecah_param_value
 113  113  #define ipsecah_log_unknown_spi         ipsecah_params[12].ipsecah_param_value
 114  114  
 115  115  #define ah0dbg(a)       printf a
 116  116  /* NOTE:  != 0 instead of > 0 so lint doesn't complain. */
 117  117  #define ah1dbg(ahstack, a)      if (ahstack->ipsecah_debug != 0) printf a
 118  118  #define ah2dbg(ahstack, a)      if (ahstack->ipsecah_debug > 1) printf a
 119  119  #define ah3dbg(ahstack, a)      if (ahstack->ipsecah_debug > 2) printf a
 120  120  
 121  121  /*
 122  122   * XXX This is broken. Padding should be determined dynamically
 123  123   * depending on the ICV size and IP version number so that the
 124  124   * total AH header size is a multiple of 32 bits or 64 bits
 125  125   * for V4 and V6 respectively. For 96bit ICVs we have no problems.
 126  126   * Anything different from that, we need to fix our code.
 127  127   */
 128  128  #define IPV4_PADDING_ALIGN      0x04    /* Multiple of 32 bits */
 129  129  #define IPV6_PADDING_ALIGN      0x04    /* Multiple of 32 bits */
 130  130  
 131  131  /*
 132  132   * Helper macro. Avoids a call to msgdsize if there is only one
 133  133   * mblk in the chain.
 134  134   */
 135  135  #define AH_MSGSIZE(mp) ((mp)->b_cont != NULL ? msgdsize(mp) : MBLKL(mp))
 136  136  
 137  137  
 138  138  static mblk_t *ah_auth_out_done(mblk_t *, ip_xmit_attr_t *, ipsec_crypto_t *);
 139  139  static mblk_t *ah_auth_in_done(mblk_t *, ip_recv_attr_t *, ipsec_crypto_t *);
 140  140  static mblk_t *ah_process_ip_options_v4(mblk_t *, ipsa_t *, int *, uint_t,
 141  141      boolean_t, ipsecah_stack_t *);
 142  142  static mblk_t *ah_process_ip_options_v6(mblk_t *, ipsa_t *, int *, uint_t,
 143  143      boolean_t, ipsecah_stack_t *);
 144  144  static void ah_getspi(mblk_t *, keysock_in_t *, ipsecah_stack_t *);
 145  145  static void ah_inbound_restart(mblk_t *, ip_recv_attr_t *);
 146  146  
 147  147  static mblk_t *ah_outbound(mblk_t *, ip_xmit_attr_t *);
 148  148  static void ah_outbound_finish(mblk_t *, ip_xmit_attr_t *);
 149  149  
 150  150  static int ipsecah_open(queue_t *, dev_t *, int, int, cred_t *);
 151  151  static int ipsecah_close(queue_t *);
 152  152  static void ipsecah_wput(queue_t *, mblk_t *);
 153  153  static void ah_send_acquire(ipsacq_t *, mblk_t *, netstack_t *);
 154  154  static boolean_t ah_register_out(uint32_t, uint32_t, uint_t, ipsecah_stack_t *,
 155  155      cred_t *);
 156  156  static void     *ipsecah_stack_init(netstackid_t stackid, netstack_t *ns);
 157  157  static void     ipsecah_stack_fini(netstackid_t stackid, void *arg);
 158  158  
 159  159  /* Setable in /etc/system */
 160  160  uint32_t ah_hash_size = IPSEC_DEFAULT_HASH_SIZE;
 161  161  
 162  162  static taskq_t *ah_taskq;
 163  163  
 164  164  static struct module_info info = {
 165  165          5136, "ipsecah", 0, INFPSZ, 65536, 1024
 166  166  };
 167  167  
 168  168  static struct qinit rinit = {
 169  169          (pfi_t)putnext, NULL, ipsecah_open, ipsecah_close, NULL, &info,
 170  170          NULL
 171  171  };
 172  172  
 173  173  static struct qinit winit = {
 174  174          (pfi_t)ipsecah_wput, NULL, ipsecah_open, ipsecah_close, NULL, &info,
 175  175          NULL
 176  176  };
 177  177  
 178  178  struct streamtab ipsecahinfo = {
 179  179          &rinit, &winit, NULL, NULL
 180  180  };
 181  181  
 182  182  static int ah_kstat_update(kstat_t *, int);
 183  183  
 184  184  uint64_t ipsacq_maxpackets = IPSACQ_MAXPACKETS;
 185  185  
 186  186  static boolean_t
 187  187  ah_kstat_init(ipsecah_stack_t *ahstack, netstackid_t stackid)
 188  188  {
 189  189          ipsec_stack_t   *ipss = ahstack->ipsecah_netstack->netstack_ipsec;
 190  190  
 191  191          ahstack->ah_ksp = kstat_create_netstack("ipsecah", 0, "ah_stat", "net",
 192  192              KSTAT_TYPE_NAMED, sizeof (ah_kstats_t) / sizeof (kstat_named_t),
 193  193              KSTAT_FLAG_PERSISTENT, stackid);
 194  194  
 195  195          if (ahstack->ah_ksp == NULL || ahstack->ah_ksp->ks_data == NULL)
 196  196                  return (B_FALSE);
 197  197  
 198  198          ahstack->ah_kstats = ahstack->ah_ksp->ks_data;
 199  199  
 200  200          ahstack->ah_ksp->ks_update = ah_kstat_update;
 201  201          ahstack->ah_ksp->ks_private = (void *)(uintptr_t)stackid;
 202  202  
 203  203  #define K64 KSTAT_DATA_UINT64
 204  204  #define KI(x) kstat_named_init(&(ahstack->ah_kstats->ah_stat_##x), #x, K64)
 205  205  
 206  206          KI(num_aalgs);
 207  207          KI(good_auth);
 208  208          KI(bad_auth);
 209  209          KI(replay_failures);
 210  210          KI(replay_early_failures);
 211  211          KI(keysock_in);
 212  212          KI(out_requests);
 213  213          KI(acquire_requests);
 214  214          KI(bytes_expired);
 215  215          KI(out_discards);
 216  216          KI(crypto_sync);
 217  217          KI(crypto_async);
 218  218          KI(crypto_failures);
 219  219  
 220  220  #undef KI
 221  221  #undef K64
 222  222  
 223  223          kstat_install(ahstack->ah_ksp);
 224  224          IP_ACQUIRE_STAT(ipss, maxpackets, ipsacq_maxpackets);
 225  225          return (B_TRUE);
 226  226  }
 227  227  
 228  228  static int
 229  229  ah_kstat_update(kstat_t *kp, int rw)
 230  230  {
 231  231          ah_kstats_t     *ekp;
 232  232          netstackid_t    stackid = (netstackid_t)(uintptr_t)kp->ks_private;
 233  233          netstack_t      *ns;
 234  234          ipsec_stack_t   *ipss;
 235  235  
 236  236          if ((kp == NULL) || (kp->ks_data == NULL))
 237  237                  return (EIO);
 238  238  
 239  239          if (rw == KSTAT_WRITE)
 240  240                  return (EACCES);
 241  241  
 242  242          ns = netstack_find_by_stackid(stackid);
 243  243          if (ns == NULL)
 244  244                  return (-1);
 245  245          ipss = ns->netstack_ipsec;
 246  246          if (ipss == NULL) {
 247  247                  netstack_rele(ns);
 248  248                  return (-1);
 249  249          }
 250  250          ekp = (ah_kstats_t *)kp->ks_data;
 251  251  
 252  252          mutex_enter(&ipss->ipsec_alg_lock);
 253  253          ekp->ah_stat_num_aalgs.value.ui64 = ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
 254  254          mutex_exit(&ipss->ipsec_alg_lock);
 255  255  
 256  256          netstack_rele(ns);
 257  257          return (0);
 258  258  }
 259  259  
 260  260  /*
 261  261   * Don't have to lock ipsec_age_interval, as only one thread will access it at
 262  262   * a time, because I control the one function that does a qtimeout() on
 263  263   * ah_pfkey_q.
 264  264   */
 265  265  static void
 266  266  ah_ager(void *arg)
 267  267  {
 268  268          ipsecah_stack_t *ahstack = (ipsecah_stack_t *)arg;
 269  269          netstack_t      *ns = ahstack->ipsecah_netstack;
 270  270          hrtime_t begin = gethrtime();
 271  271  
 272  272          sadb_ager(&ahstack->ah_sadb.s_v4, ahstack->ah_pfkey_q,
 273  273              ahstack->ipsecah_reap_delay, ns);
 274  274          sadb_ager(&ahstack->ah_sadb.s_v6, ahstack->ah_pfkey_q,
 275  275              ahstack->ipsecah_reap_delay, ns);
 276  276  
 277  277          ahstack->ah_event = sadb_retimeout(begin, ahstack->ah_pfkey_q,
 278  278              ah_ager, ahstack,
 279  279              &ahstack->ipsecah_age_interval, ahstack->ipsecah_age_int_max,
 280  280              info.mi_idnum);
 281  281  }
 282  282  
 283  283  /*
 284  284   * Get an AH NDD parameter.
 285  285   */
 286  286  /* ARGSUSED */
 287  287  static int
 288  288  ipsecah_param_get(q, mp, cp, cr)
 289  289          queue_t *q;
 290  290          mblk_t  *mp;
 291  291          caddr_t cp;
 292  292          cred_t *cr;
 293  293  {
 294  294          ipsecahparam_t  *ipsecahpa = (ipsecahparam_t *)cp;
 295  295          uint_t value;
 296  296          ipsecah_stack_t *ahstack = (ipsecah_stack_t *)q->q_ptr;
 297  297  
 298  298          mutex_enter(&ahstack->ipsecah_param_lock);
 299  299          value = ipsecahpa->ipsecah_param_value;
 300  300          mutex_exit(&ahstack->ipsecah_param_lock);
 301  301  
 302  302          (void) mi_mpprintf(mp, "%u", value);
 303  303          return (0);
 304  304  }
 305  305  
 306  306  /*
 307  307   * This routine sets an NDD variable in a ipsecahparam_t structure.
 308  308   */
 309  309  /* ARGSUSED */
 310  310  static int
 311  311  ipsecah_param_set(q, mp, value, cp, cr)
 312  312          queue_t *q;
 313  313          mblk_t  *mp;
 314  314          char    *value;
 315  315          caddr_t cp;
 316  316          cred_t *cr;
 317  317  {
 318  318          ulong_t new_value;
 319  319          ipsecahparam_t  *ipsecahpa = (ipsecahparam_t *)cp;
 320  320          ipsecah_stack_t *ahstack = (ipsecah_stack_t *)q->q_ptr;
 321  321  
 322  322          /*
 323  323           * Fail the request if the new value does not lie within the
 324  324           * required bounds.
 325  325           */
 326  326          if (ddi_strtoul(value, NULL, 10, &new_value) != 0 ||
 327  327              new_value < ipsecahpa->ipsecah_param_min ||
 328  328              new_value > ipsecahpa->ipsecah_param_max) {
 329  329                      return (EINVAL);
 330  330          }
 331  331  
 332  332          /* Set the new value */
 333  333          mutex_enter(&ahstack->ipsecah_param_lock);
 334  334          ipsecahpa->ipsecah_param_value = new_value;
 335  335          mutex_exit(&ahstack->ipsecah_param_lock);
 336  336          return (0);
 337  337  }
 338  338  
 339  339  /*
 340  340   * Using lifetime NDD variables, fill in an extended combination's
 341  341   * lifetime information.
 342  342   */
 343  343  void
 344  344  ipsecah_fill_defs(sadb_x_ecomb_t *ecomb, netstack_t *ns)
 345  345  {
 346  346          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
 347  347  
 348  348          ecomb->sadb_x_ecomb_soft_bytes = ahstack->ipsecah_default_soft_bytes;
 349  349          ecomb->sadb_x_ecomb_hard_bytes = ahstack->ipsecah_default_hard_bytes;
 350  350          ecomb->sadb_x_ecomb_soft_addtime =
 351  351              ahstack->ipsecah_default_soft_addtime;
 352  352          ecomb->sadb_x_ecomb_hard_addtime =
 353  353              ahstack->ipsecah_default_hard_addtime;
 354  354          ecomb->sadb_x_ecomb_soft_usetime =
 355  355              ahstack->ipsecah_default_soft_usetime;
 356  356          ecomb->sadb_x_ecomb_hard_usetime =
 357  357              ahstack->ipsecah_default_hard_usetime;
 358  358  }
 359  359  
 360  360  /*
 361  361   * Initialize things for AH at module load time.
 362  362   */
 363  363  boolean_t
 364  364  ipsecah_ddi_init(void)
 365  365  {
 366  366          ah_taskq = taskq_create("ah_taskq", 1, minclsyspri,
 367  367              IPSEC_TASKQ_MIN, IPSEC_TASKQ_MAX, 0);
 368  368  
 369  369          /*
 370  370           * We want to be informed each time a stack is created or
 371  371           * destroyed in the kernel, so we can maintain the
 372  372           * set of ipsecah_stack_t's.
 373  373           */
 374  374          netstack_register(NS_IPSECAH, ipsecah_stack_init, NULL,
 375  375              ipsecah_stack_fini);
 376  376  
 377  377          return (B_TRUE);
 378  378  }
 379  379  
 380  380  /*
 381  381   * Walk through the param array specified registering each element with the
 382  382   * named dispatch handler.
 383  383   */
 384  384  static boolean_t
 385  385  ipsecah_param_register(IDP *ndp, ipsecahparam_t *ahp, int cnt)
 386  386  {
 387  387          for (; cnt-- > 0; ahp++) {
 388  388                  if (ahp->ipsecah_param_name != NULL &&
 389  389                      ahp->ipsecah_param_name[0]) {
 390  390                          if (!nd_load(ndp,
 391  391                              ahp->ipsecah_param_name,
 392  392                              ipsecah_param_get, ipsecah_param_set,
 393  393                              (caddr_t)ahp)) {
 394  394                                  nd_free(ndp);
 395  395                                  return (B_FALSE);
 396  396                          }
 397  397                  }
 398  398          }
 399  399          return (B_TRUE);
 400  400  }
 401  401  
 402  402  /*
 403  403   * Initialize things for AH for each stack instance
 404  404   */
 405  405  static void *
 406  406  ipsecah_stack_init(netstackid_t stackid, netstack_t *ns)
 407  407  {
 408  408          ipsecah_stack_t *ahstack;
 409  409          ipsecahparam_t  *ahp;
 410  410  
 411  411          ahstack = (ipsecah_stack_t *)kmem_zalloc(sizeof (*ahstack), KM_SLEEP);
 412  412          ahstack->ipsecah_netstack = ns;
 413  413  
 414  414          ahp = (ipsecahparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP);
 415  415          ahstack->ipsecah_params = ahp;
 416  416          bcopy(lcl_param_arr, ahp, sizeof (lcl_param_arr));
 417  417  
 418  418          (void) ipsecah_param_register(&ahstack->ipsecah_g_nd, ahp,
 419  419              A_CNT(lcl_param_arr));
 420  420  
 421  421          (void) ah_kstat_init(ahstack, stackid);
 422  422  
 423  423          ahstack->ah_sadb.s_acquire_timeout = &ahstack->ipsecah_acquire_timeout;
 424  424          ahstack->ah_sadb.s_acqfn = ah_send_acquire;
 425  425          sadbp_init("AH", &ahstack->ah_sadb, SADB_SATYPE_AH, ah_hash_size,
 426  426              ahstack->ipsecah_netstack);
 427  427  
 428  428          mutex_init(&ahstack->ipsecah_param_lock, NULL, MUTEX_DEFAULT, 0);
 429  429  
 430  430          ip_drop_register(&ahstack->ah_dropper, "IPsec AH");
 431  431          return (ahstack);
 432  432  }
 433  433  
 434  434  /*
 435  435   * Destroy things for AH at module unload time.
 436  436   */
 437  437  void
 438  438  ipsecah_ddi_destroy(void)
 439  439  {
 440  440          netstack_unregister(NS_IPSECAH);
 441  441          taskq_destroy(ah_taskq);
 442  442  }
 443  443  
 444  444  /*
 445  445   * Destroy things for AH for one stack... Never called?
 446  446   */
 447  447  static void
 448  448  ipsecah_stack_fini(netstackid_t stackid, void *arg)
 449  449  {
 450  450          ipsecah_stack_t *ahstack = (ipsecah_stack_t *)arg;
 451  451  
 452  452          if (ahstack->ah_pfkey_q != NULL) {
 453  453                  (void) quntimeout(ahstack->ah_pfkey_q, ahstack->ah_event);
 454  454          }
 455  455          ahstack->ah_sadb.s_acqfn = NULL;
 456  456          ahstack->ah_sadb.s_acquire_timeout = NULL;
 457  457          sadbp_destroy(&ahstack->ah_sadb, ahstack->ipsecah_netstack);
 458  458          ip_drop_unregister(&ahstack->ah_dropper);
 459  459          mutex_destroy(&ahstack->ipsecah_param_lock);
 460  460          nd_free(&ahstack->ipsecah_g_nd);
 461  461  
 462  462          kmem_free(ahstack->ipsecah_params, sizeof (lcl_param_arr));
 463  463          ahstack->ipsecah_params = NULL;
 464  464          kstat_delete_netstack(ahstack->ah_ksp, stackid);
 465  465          ahstack->ah_ksp = NULL;
 466  466          ahstack->ah_kstats = NULL;
 467  467  
 468  468          kmem_free(ahstack, sizeof (*ahstack));
 469  469  }
 470  470  
 471  471  /*
 472  472   * AH module open routine, which is here for keysock plumbing.
 473  473   * Keysock is pushed over {AH,ESP} which is an artifact from the Bad Old
 474  474   * Days of export control, and fears that ESP would not be allowed
 475  475   * to be shipped at all by default.  Eventually, keysock should
 476  476   * either access AH and ESP via modstubs or krtld dependencies, or
 477  477   * perhaps be folded in with AH and ESP into a single IPsec/netsec
 478  478   * module ("netsec" if PF_KEY provides more than AH/ESP keying tables).
 479  479   */
 480  480  /* ARGSUSED */
 481  481  static int
 482  482  ipsecah_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
 483  483  {
 484  484          netstack_t      *ns;
 485  485          ipsecah_stack_t *ahstack;
 486  486  
 487  487          if (secpolicy_ip_config(credp, B_FALSE) != 0)
 488  488                  return (EPERM);
 489  489  
 490  490          if (q->q_ptr != NULL)
 491  491                  return (0);  /* Re-open of an already open instance. */
 492  492  
 493  493          if (sflag != MODOPEN)
 494  494                  return (EINVAL);
 495  495  
 496  496          ns = netstack_find_by_cred(credp);
 497  497          ASSERT(ns != NULL);
 498  498          ahstack = ns->netstack_ipsecah;
 499  499          ASSERT(ahstack != NULL);
 500  500  
 501  501          q->q_ptr = ahstack;
 502  502          WR(q)->q_ptr = q->q_ptr;
 503  503  
 504  504          qprocson(q);
 505  505          return (0);
 506  506  }
 507  507  
 508  508  /*
 509  509   * AH module close routine.
 510  510   */
 511  511  static int
 512  512  ipsecah_close(queue_t *q)
 513  513  {
 514  514          ipsecah_stack_t *ahstack = (ipsecah_stack_t *)q->q_ptr;
 515  515  
 516  516          /*
 517  517           * Clean up q_ptr, if needed.
 518  518           */
 519  519          qprocsoff(q);
 520  520  
 521  521          /* Keysock queue check is safe, because of OCEXCL perimeter. */
 522  522  
 523  523          if (q == ahstack->ah_pfkey_q) {
 524  524                  ah1dbg(ahstack,
 525  525                      ("ipsecah_close:  Ummm... keysock is closing AH.\n"));
 526  526                  ahstack->ah_pfkey_q = NULL;
 527  527                  /* Detach qtimeouts. */
 528  528                  (void) quntimeout(q, ahstack->ah_event);
 529  529          }
 530  530  
 531  531          netstack_rele(ahstack->ipsecah_netstack);
 532  532          return (0);
 533  533  }
 534  534  
 535  535  /*
 536  536   * Construct an SADB_REGISTER message with the current algorithms.
 537  537   */
 538  538  static boolean_t
 539  539  ah_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
 540  540      ipsecah_stack_t *ahstack, cred_t *cr)
 541  541  {
 542  542          mblk_t *mp;
 543  543          boolean_t rc = B_TRUE;
 544  544          sadb_msg_t *samsg;
 545  545          sadb_supported_t *sasupp;
 546  546          sadb_alg_t *saalg;
 547  547          uint_t allocsize = sizeof (*samsg);
 548  548          uint_t i, numalgs_snap;
 549  549          ipsec_alginfo_t **authalgs;
 550  550          uint_t num_aalgs;
 551  551          ipsec_stack_t   *ipss = ahstack->ipsecah_netstack->netstack_ipsec;
 552  552          sadb_sens_t *sens;
 553  553          size_t sens_len = 0;
 554  554          sadb_ext_t *nextext;
 555  555          ts_label_t *sens_tsl = NULL;
 556  556  
 557  557          /* Allocate the KEYSOCK_OUT. */
 558  558          mp = sadb_keysock_out(serial);
 559  559          if (mp == NULL) {
 560  560                  ah0dbg(("ah_register_out: couldn't allocate mblk.\n"));
 561  561                  return (B_FALSE);
 562  562          }
 563  563  
 564  564          if (is_system_labeled() && (cr != NULL)) {
 565  565                  sens_tsl = crgetlabel(cr);
 566  566                  if (sens_tsl != NULL) {
 567  567                          sens_len = sadb_sens_len_from_label(sens_tsl);
 568  568                          allocsize += sens_len;
 569  569                  }
 570  570          }
 571  571  
 572  572          /*
 573  573           * Allocate the PF_KEY message that follows KEYSOCK_OUT.
 574  574           * The alg reader lock needs to be held while allocating
 575  575           * the variable part (i.e. the algorithms) of the message.
 576  576           */
 577  577  
 578  578          mutex_enter(&ipss->ipsec_alg_lock);
 579  579  
 580  580          /*
 581  581           * Return only valid algorithms, so the number of algorithms
 582  582           * to send up may be less than the number of algorithm entries
 583  583           * in the table.
 584  584           */
 585  585          authalgs = ipss->ipsec_alglists[IPSEC_ALG_AUTH];
 586  586          for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
 587  587                  if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
 588  588                          num_aalgs++;
 589  589  
 590  590          /*
 591  591           * Fill SADB_REGISTER message's algorithm descriptors.  Hold
 592  592           * down the lock while filling it.
 593  593           */
 594  594          if (num_aalgs != 0) {
 595  595                  allocsize += (num_aalgs * sizeof (*saalg));
 596  596                  allocsize += sizeof (*sasupp);
 597  597          }
 598  598          mp->b_cont = allocb(allocsize, BPRI_HI);
 599  599          if (mp->b_cont == NULL) {
 600  600                  mutex_exit(&ipss->ipsec_alg_lock);
 601  601                  freemsg(mp);
 602  602                  return (B_FALSE);
 603  603          }
 604  604  
 605  605          mp->b_cont->b_wptr += allocsize;
 606  606          nextext = (sadb_ext_t *)(mp->b_cont->b_rptr + sizeof (*samsg));
 607  607  
 608  608          if (num_aalgs != 0) {
 609  609  
 610  610                  saalg = (sadb_alg_t *)(((uint8_t *)nextext) + sizeof (*sasupp));
 611  611                  ASSERT(((ulong_t)saalg & 0x7) == 0);
 612  612  
 613  613                  numalgs_snap = 0;
 614  614                  for (i = 0;
 615  615                      ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs));
 616  616                      i++) {
 617  617                          if (authalgs[i] == NULL || !ALG_VALID(authalgs[i]))
 618  618                                  continue;
 619  619  
 620  620                          saalg->sadb_alg_id = authalgs[i]->alg_id;
 621  621                          saalg->sadb_alg_ivlen = 0;
 622  622                          saalg->sadb_alg_minbits = authalgs[i]->alg_ef_minbits;
 623  623                          saalg->sadb_alg_maxbits = authalgs[i]->alg_ef_maxbits;
 624  624                          saalg->sadb_x_alg_increment =
 625  625                              authalgs[i]->alg_increment;
 626  626                          /* For now, salt is meaningless in AH. */
 627  627                          ASSERT(authalgs[i]->alg_saltlen == 0);
 628  628                          saalg->sadb_x_alg_saltbits =
 629  629                              SADB_8TO1(authalgs[i]->alg_saltlen);
 630  630                          numalgs_snap++;
 631  631                          saalg++;
 632  632                  }
 633  633                  ASSERT(numalgs_snap == num_aalgs);
 634  634  #ifdef DEBUG
 635  635                  /*
 636  636                   * Reality check to make sure I snagged all of the
 637  637                   * algorithms.
 638  638                   */
 639  639                  for (; i < IPSEC_MAX_ALGS; i++)
 640  640                          if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
 641  641                                  cmn_err(CE_PANIC,
 642  642                                      "ah_register_out()!  Missed #%d.\n", i);
 643  643  #endif /* DEBUG */
 644  644                  nextext = (sadb_ext_t *)saalg;
 645  645          }
 646  646  
 647  647          mutex_exit(&ipss->ipsec_alg_lock);
 648  648  
 649  649          if (sens_tsl != NULL) {
 650  650                  sens = (sadb_sens_t *)nextext;
 651  651                  sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY,
 652  652                      sens_tsl, sens_len);
 653  653  
 654  654                  nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
 655  655          }
 656  656  
 657  657          /* Now fill the restof the SADB_REGISTER message. */
 658  658  
 659  659          samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
 660  660          samsg->sadb_msg_version = PF_KEY_V2;
 661  661          samsg->sadb_msg_type = SADB_REGISTER;
 662  662          samsg->sadb_msg_errno = 0;
 663  663          samsg->sadb_msg_satype = SADB_SATYPE_AH;
 664  664          samsg->sadb_msg_len = SADB_8TO64(allocsize);
 665  665          samsg->sadb_msg_reserved = 0;
 666  666          /*
 667  667           * Assume caller has sufficient sequence/pid number info.  If it's one
 668  668           * from me over a new alg., I could give two hoots about sequence.
 669  669           */
 670  670          samsg->sadb_msg_seq = sequence;
 671  671          samsg->sadb_msg_pid = pid;
 672  672  
 673  673          if (num_aalgs != 0) {
 674  674                  sasupp = (sadb_supported_t *)(samsg + 1);
 675  675                  sasupp->sadb_supported_len = SADB_8TO64(
 676  676                      sizeof (*sasupp) + sizeof (*saalg) * num_aalgs);
 677  677                  sasupp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
 678  678                  sasupp->sadb_supported_reserved = 0;
 679  679          }
 680  680  
 681  681          if (ahstack->ah_pfkey_q != NULL)
 682  682                  putnext(ahstack->ah_pfkey_q, mp);
 683  683          else {
 684  684                  rc = B_FALSE;
 685  685                  freemsg(mp);
 686  686          }
 687  687  
 688  688          return (rc);
 689  689  }
 690  690  
 691  691  /*
 692  692   * Invoked when the algorithm table changes. Causes SADB_REGISTER
 693  693   * messages continaining the current list of algorithms to be
 694  694   * sent up to the AH listeners.
 695  695   */
 696  696  void
 697  697  ipsecah_algs_changed(netstack_t *ns)
 698  698  {
 699  699          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
 700  700  
 701  701          /*
 702  702           * Time to send a PF_KEY SADB_REGISTER message to AH listeners
 703  703           * everywhere.  (The function itself checks for NULL ah_pfkey_q.)
 704  704           */
 705  705          (void) ah_register_out(0, 0, 0, ahstack, NULL);
 706  706  }
 707  707  
 708  708  /*
 709  709   * Stub function that taskq_dispatch() invokes to take the mblk (in arg)
 710  710   * and send it into AH and IP again.
 711  711   */
 712  712  static void
 713  713  inbound_task(void *arg)
 714  714  {
 715  715          mblk_t          *mp = (mblk_t *)arg;
 716  716          mblk_t          *async_mp;
 717  717          ip_recv_attr_t  iras;
 718  718  
 719  719          async_mp = mp;
 720  720          mp = async_mp->b_cont;
 721  721          async_mp->b_cont = NULL;
 722  722          if (!ip_recv_attr_from_mblk(async_mp, &iras)) {
 723  723                  /* The ill or ip_stack_t disappeared on us */
 724  724                  ip_drop_input("ip_recv_attr_from_mblk", mp, NULL);
 725  725                  freemsg(mp);
 726  726                  goto done;
 727  727          }
 728  728  
 729  729          ah_inbound_restart(mp, &iras);
 730  730  done:
 731  731          ira_cleanup(&iras, B_TRUE);
 732  732  }
 733  733  
 734  734  /*
 735  735   * Restart ESP after the SA has been added.
 736  736   */
 737  737  static void
 738  738  ah_inbound_restart(mblk_t *mp, ip_recv_attr_t *ira)
 739  739  {
 740  740          ah_t            *ah;
 741  741          netstack_t      *ns;
 742  742          ipsecah_stack_t *ahstack;
 743  743  
 744  744          ns = ira->ira_ill->ill_ipst->ips_netstack;
 745  745          ahstack = ns->netstack_ipsecah;
 746  746  
 747  747          ASSERT(ahstack != NULL);
 748  748          mp = ipsec_inbound_ah_sa(mp, ira, &ah);
 749  749          if (mp == NULL)
 750  750                  return;
 751  751  
 752  752          ASSERT(ah != NULL);
 753  753          ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE);
 754  754          ASSERT(ira->ira_ipsec_ah_sa != NULL);
 755  755  
 756  756          mp = ira->ira_ipsec_ah_sa->ipsa_input_func(mp, ah, ira);
 757  757          if (mp == NULL) {
 758  758                  /*
 759  759                   * Either it failed or is pending. In the former case
 760  760                   * ipIfStatsInDiscards was increased.
 761  761                   */
 762  762                  return;
 763  763          }
 764  764          ip_input_post_ipsec(mp, ira);
 765  765  }
 766  766  
 767  767  /*
 768  768   * Now that weak-key passed, actually ADD the security association, and
 769  769   * send back a reply ADD message.
 770  770   */
 771  771  static int
 772  772  ah_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi,
 773  773      int *diagnostic, ipsecah_stack_t *ahstack)
 774  774  {
 775  775          isaf_t *primary = NULL, *secondary;
 776  776          boolean_t clone = B_FALSE, is_inbound = B_FALSE;
 777  777          sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
 778  778          ipsa_t *larval;
 779  779          ipsacq_t *acqrec;
 780  780          iacqf_t *acq_bucket;
 781  781          mblk_t *acq_msgs = NULL;
 782  782          mblk_t *lpkt;
 783  783          int rc;
 784  784          ipsa_query_t sq;
 785  785          int error;
 786  786          netstack_t      *ns = ahstack->ipsecah_netstack;
 787  787          ipsec_stack_t   *ipss = ns->netstack_ipsec;
 788  788  
 789  789          /*
 790  790           * Locate the appropriate table(s).
 791  791           */
 792  792  
 793  793          sq.spp = &ahstack->ah_sadb;
 794  794          error = sadb_form_query(ksi, IPSA_Q_SA|IPSA_Q_DST,
 795  795              IPSA_Q_SA|IPSA_Q_DST|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
 796  796              &sq, diagnostic);
 797  797          if (error)
 798  798                  return (error);
 799  799  
 800  800          /*
 801  801           * Use the direction flags provided by the KMD to determine
 802  802           * if the inbound or outbound table should be the primary
 803  803           * for this SA. If these flags were absent then make this
 804  804           * decision based on the addresses.
 805  805           */
 806  806          if (assoc->sadb_sa_flags & IPSA_F_INBOUND) {
 807  807                  primary = sq.inbound;
 808  808                  secondary = sq.outbound;
 809  809                  is_inbound = B_TRUE;
 810  810                  if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND)
 811  811                          clone = B_TRUE;
 812  812          } else {
 813  813                  if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND) {
 814  814                          primary = sq.outbound;
 815  815                          secondary = sq.inbound;
 816  816                  }
 817  817          }
 818  818          if (primary == NULL) {
 819  819                  /*
 820  820                   * The KMD did not set a direction flag, determine which
 821  821                   * table to insert the SA into based on addresses.
 822  822                   */
 823  823                  switch (ksi->ks_in_dsttype) {
 824  824                  case KS_IN_ADDR_MBCAST:
 825  825                          clone = B_TRUE; /* All mcast SAs can be bidirectional */
 826  826                          assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
 827  827                          /* FALLTHRU */
 828  828                  /*
 829  829                   * If the source address is either one of mine, or unspecified
 830  830                   * (which is best summed up by saying "not 'not mine'"),
 831  831                   * then the association is potentially bi-directional,
 832  832                   * in that it can be used for inbound traffic and outbound
 833  833                   * traffic.  The best example of such and SA is a multicast
 834  834                   * SA (which allows me to receive the outbound traffic).
 835  835                   */
 836  836                  case KS_IN_ADDR_ME:
 837  837                          assoc->sadb_sa_flags |= IPSA_F_INBOUND;
 838  838                          primary = sq.inbound;
 839  839                          secondary = sq.outbound;
 840  840                          if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME)
 841  841                                  clone = B_TRUE;
 842  842                          is_inbound = B_TRUE;
 843  843                          break;
 844  844  
 845  845                  /*
 846  846                   * If the source address literally not mine (either
 847  847                   * unspecified or not mine), then this SA may have an
 848  848                   * address that WILL be mine after some configuration.
 849  849                   * We pay the price for this by making it a bi-directional
 850  850                   * SA.
 851  851                   */
 852  852                  case KS_IN_ADDR_NOTME:
 853  853                          assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
 854  854                          primary = sq.outbound;
 855  855                          secondary = sq.inbound;
 856  856                          if (ksi->ks_in_srctype != KS_IN_ADDR_ME) {
 857  857                                  assoc->sadb_sa_flags |= IPSA_F_INBOUND;
 858  858                                  clone = B_TRUE;
 859  859                          }
 860  860                          break;
 861  861                  default:
 862  862                          *diagnostic = SADB_X_DIAGNOSTIC_BAD_DST;
 863  863                          return (EINVAL);
 864  864                  }
 865  865          }
 866  866  
 867  867          /*
 868  868           * Find a ACQUIRE list entry if possible.  If we've added an SA that
 869  869           * suits the needs of an ACQUIRE list entry, we can eliminate the
 870  870           * ACQUIRE list entry and transmit the enqueued packets.  Use the
 871  871           * high-bit of the sequence number to queue it.  Key off destination
 872  872           * addr, and change acqrec's state.
 873  873           */
 874  874  
 875  875          if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) {
 876  876                  acq_bucket = &(sq.sp->sdb_acq[sq.outhash]);
 877  877                  mutex_enter(&acq_bucket->iacqf_lock);
 878  878                  for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL;
 879  879                      acqrec = acqrec->ipsacq_next) {
 880  880                          mutex_enter(&acqrec->ipsacq_lock);
 881  881                          /*
 882  882                           * Q:  I only check sequence.  Should I check dst?
 883  883                           * A: Yes, check dest because those are the packets
 884  884                           *    that are queued up.
 885  885                           */
 886  886                          if (acqrec->ipsacq_seq == samsg->sadb_msg_seq &&
 887  887                              IPSA_ARE_ADDR_EQUAL(sq.dstaddr,
 888  888                              acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam))
 889  889                                  break;
 890  890                          mutex_exit(&acqrec->ipsacq_lock);
 891  891                  }
 892  892                  if (acqrec != NULL) {
 893  893                          /*
 894  894                           * AHA!  I found an ACQUIRE record for this SA.
 895  895                           * Grab the msg list, and free the acquire record.
 896  896                           * I already am holding the lock for this record,
 897  897                           * so all I have to do is free it.
 898  898                           */
 899  899                          acq_msgs = acqrec->ipsacq_mp;
 900  900                          acqrec->ipsacq_mp = NULL;
 901  901                          mutex_exit(&acqrec->ipsacq_lock);
 902  902                          sadb_destroy_acquire(acqrec, ns);
 903  903                  }
 904  904                  mutex_exit(&acq_bucket->iacqf_lock);
 905  905          }
 906  906  
 907  907          /*
 908  908           * Find PF_KEY message, and see if I'm an update.  If so, find entry
 909  909           * in larval list (if there).
 910  910           */
 911  911  
 912  912          larval = NULL;
 913  913  
 914  914          if (samsg->sadb_msg_type == SADB_UPDATE) {
 915  915                  mutex_enter(&sq.inbound->isaf_lock);
 916  916                  larval = ipsec_getassocbyspi(sq.inbound, sq.assoc->sadb_sa_spi,
 917  917                      ALL_ZEROES_PTR, sq.dstaddr, sq.dst->sin_family);
 918  918                  mutex_exit(&sq.inbound->isaf_lock);
 919  919  
 920  920                  if ((larval == NULL) ||
 921  921                      (larval->ipsa_state != IPSA_STATE_LARVAL)) {
 922  922                          *diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
 923  923                          if (larval != NULL) {
 924  924                                  IPSA_REFRELE(larval);
 925  925                          }
 926  926                          ah0dbg(("Larval update, but larval disappeared.\n"));
 927  927                          return (ESRCH);
 928  928                  } /* Else sadb_common_add unlinks it for me! */
 929  929          }
 930  930  
 931  931          if (larval != NULL) {
 932  932                  /*
 933  933                   * Hold again, because sadb_common_add() consumes a reference,
 934  934                   * and we don't want to clear_lpkt() without a reference.
 935  935                   */
 936  936                  IPSA_REFHOLD(larval);
 937  937          }
 938  938  
 939  939          rc = sadb_common_add(ahstack->ah_pfkey_q, mp,
 940  940              samsg, ksi, primary, secondary, larval, clone, is_inbound,
 941  941              diagnostic, ns, &ahstack->ah_sadb);
 942  942  
 943  943          if (larval != NULL) {
 944  944                  if (rc == 0) {
 945  945                          lpkt = sadb_clear_lpkt(larval);
 946  946                          if (lpkt != NULL) {
 947  947                                  rc = !taskq_dispatch(ah_taskq, inbound_task,
 948  948                                      lpkt, TQ_NOSLEEP);
 949  949                          }
 950  950                  }
 951  951                  IPSA_REFRELE(larval);
 952  952          }
 953  953  
 954  954          /*
 955  955           * How much more stack will I create with all of these
 956  956           * ah_outbound_*() calls?
 957  957           */
 958  958  
 959  959          /* Handle the packets queued waiting for the SA */
 960  960          while (acq_msgs != NULL) {
 961  961                  mblk_t          *asyncmp;
 962  962                  mblk_t          *data_mp;
 963  963                  ip_xmit_attr_t  ixas;
 964  964                  ill_t           *ill;
 965  965  
 966  966                  asyncmp = acq_msgs;
 967  967                  acq_msgs = acq_msgs->b_next;
 968  968                  asyncmp->b_next = NULL;
 969  969  
 970  970                  /*
 971  971                   * Extract the ip_xmit_attr_t from the first mblk.
 972  972                   * Verifies that the netstack and ill is still around; could
 973  973                   * have vanished while iked was doing its work.
 974  974                   * On succesful return we have a nce_t and the ill/ipst can't
 975  975                   * disappear until we do the nce_refrele in ixa_cleanup.
 976  976                   */
 977  977                  data_mp = asyncmp->b_cont;
 978  978                  asyncmp->b_cont = NULL;
 979  979                  if (!ip_xmit_attr_from_mblk(asyncmp, &ixas)) {
 980  980                          AH_BUMP_STAT(ahstack, out_discards);
 981  981                          ip_drop_packet(data_mp, B_FALSE, NULL,
 982  982                              DROPPER(ipss, ipds_sadb_acquire_timeout),
 983  983                              &ahstack->ah_dropper);
 984  984                  } else if (rc != 0) {
 985  985                          ill = ixas.ixa_nce->nce_ill;
 986  986                          AH_BUMP_STAT(ahstack, out_discards);
 987  987                          ip_drop_packet(data_mp, B_FALSE, ill,
 988  988                              DROPPER(ipss, ipds_sadb_acquire_timeout),
 989  989                              &ahstack->ah_dropper);
 990  990                          BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
 991  991                  } else {
 992  992                          ah_outbound_finish(data_mp, &ixas);
 993  993                  }
 994  994                  ixa_cleanup(&ixas);
 995  995          }
 996  996  
 997  997          return (rc);
 998  998  }
 999  999  
1000 1000  
1001 1001  /*
1002 1002   * Process one of the queued messages (from ipsacq_mp) once the SA
1003 1003   * has been added.
1004 1004   */
1005 1005  static void
1006 1006  ah_outbound_finish(mblk_t *data_mp, ip_xmit_attr_t *ixa)
1007 1007  {
1008 1008          netstack_t      *ns = ixa->ixa_ipst->ips_netstack;
1009 1009          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
1010 1010          ipsec_stack_t   *ipss = ns->netstack_ipsec;
1011 1011          ill_t           *ill = ixa->ixa_nce->nce_ill;
1012 1012  
1013 1013          if (!ipsec_outbound_sa(data_mp, ixa, IPPROTO_AH)) {
1014 1014                  AH_BUMP_STAT(ahstack, out_discards);
1015 1015                  ip_drop_packet(data_mp, B_FALSE, ill,
1016 1016                      DROPPER(ipss, ipds_sadb_acquire_timeout),
1017 1017                      &ahstack->ah_dropper);
1018 1018                  BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
1019 1019                  return;
1020 1020          }
1021 1021  
1022 1022          data_mp = ah_outbound(data_mp, ixa);
1023 1023          if (data_mp == NULL)
1024 1024                  return;
1025 1025  
1026 1026          (void) ip_output_post_ipsec(data_mp, ixa);
1027 1027  }
1028 1028  
1029 1029  /*
1030 1030   * Add new AH security association.  This may become a generic AH/ESP
1031 1031   * routine eventually.
1032 1032   */
1033 1033  static int
1034 1034  ah_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
1035 1035  {
1036 1036          sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
1037 1037          sadb_address_t *srcext =
1038 1038              (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
1039 1039          sadb_address_t *dstext =
1040 1040              (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
1041 1041          sadb_address_t *isrcext =
1042 1042              (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_SRC];
1043 1043          sadb_address_t *idstext =
1044 1044              (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_DST];
1045 1045          sadb_key_t *key = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
1046 1046          struct sockaddr_in *src, *dst;
1047 1047          /* We don't need sockaddr_in6 for now. */
1048 1048          sadb_lifetime_t *soft =
1049 1049              (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
1050 1050          sadb_lifetime_t *hard =
1051 1051              (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
1052 1052          sadb_lifetime_t *idle =
1053 1053              (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE];
1054 1054          ipsec_alginfo_t *aalg;
1055 1055          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
1056 1056          ipsec_stack_t   *ipss = ns->netstack_ipsec;
1057 1057  
1058 1058          /* I need certain extensions present for an ADD message. */
1059 1059          if (srcext == NULL) {
1060 1060                  *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
1061 1061                  return (EINVAL);
1062 1062          }
1063 1063          if (dstext == NULL) {
1064 1064                  *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
1065 1065                  return (EINVAL);
1066 1066          }
1067 1067          if (isrcext == NULL && idstext != NULL) {
1068 1068                  *diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_SRC;
1069 1069                  return (EINVAL);
1070 1070          }
1071 1071          if (isrcext != NULL && idstext == NULL) {
1072 1072                  *diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_DST;
1073 1073                  return (EINVAL);
1074 1074          }
1075 1075          if (assoc == NULL) {
1076 1076                  *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
1077 1077                  return (EINVAL);
1078 1078          }
1079 1079          if (key == NULL) {
  
    | 
      ↓ open down ↓ | 
    1079 lines elided | 
    
      ↑ open up ↑ | 
  
1080 1080                  *diagnostic = SADB_X_DIAGNOSTIC_MISSING_AKEY;
1081 1081                  return (EINVAL);
1082 1082          }
1083 1083  
1084 1084          src = (struct sockaddr_in *)(srcext + 1);
1085 1085          dst = (struct sockaddr_in *)(dstext + 1);
1086 1086  
1087 1087          /* Sundry ADD-specific reality checks. */
1088 1088          /* XXX STATS : Logging/stats here? */
1089 1089  
1090      -        if ((assoc->sadb_sa_state != SADB_SASTATE_MATURE) &&
1091      -            (assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE_ELSEWHERE)) {
     1090 +        if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) {
1092 1091                  *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
1093 1092                  return (EINVAL);
1094 1093          }
1095 1094          if (assoc->sadb_sa_encrypt != SADB_EALG_NONE) {
1096 1095                  *diagnostic = SADB_X_DIAGNOSTIC_ENCR_NOTSUPP;
1097 1096                  return (EINVAL);
1098 1097          }
1099 1098          if (assoc->sadb_sa_flags & ~ahstack->ah_sadb.s_addflags) {
1100 1099                  *diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS;
1101 1100                  return (EINVAL);
1102 1101          }
1103 1102          if ((*diagnostic = sadb_hardsoftchk(hard, soft, idle)) != 0)
1104 1103                  return (EINVAL);
1105 1104  
1106 1105          ASSERT(src->sin_family == dst->sin_family);
1107 1106  
1108 1107          /* Stuff I don't support, for now.  XXX Diagnostic? */
1109 1108          if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL)
1110 1109                  return (EOPNOTSUPP);
1111 1110  
1112 1111          if (ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL) {
1113 1112                  if (!is_system_labeled())
1114 1113                          return (EOPNOTSUPP);
1115 1114          }
1116 1115  
1117 1116          if (ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS] != NULL) {
1118 1117                  if (!is_system_labeled())
1119 1118                          return (EOPNOTSUPP);
1120 1119          }
1121 1120          /*
1122 1121           * XXX Policy : I'm not checking identities at this time, but
1123 1122           * if I did, I'd do them here, before I sent the weak key
1124 1123           * check up to the algorithm.
1125 1124           */
1126 1125  
1127 1126          /* verify that there is a mapping for the specified algorithm */
1128 1127          mutex_enter(&ipss->ipsec_alg_lock);
1129 1128          aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH][assoc->sadb_sa_auth];
1130 1129          if (aalg == NULL || !ALG_VALID(aalg)) {
1131 1130                  mutex_exit(&ipss->ipsec_alg_lock);
1132 1131                  ah1dbg(ahstack, ("Couldn't find auth alg #%d.\n",
1133 1132                      assoc->sadb_sa_auth));
1134 1133                  *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
1135 1134                  return (EINVAL);
1136 1135          }
1137 1136          ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
1138 1137  
1139 1138          /* sanity check key sizes */
1140 1139          if (!ipsec_valid_key_size(key->sadb_key_bits, aalg)) {
1141 1140                  mutex_exit(&ipss->ipsec_alg_lock);
1142 1141                  *diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS;
1143 1142                  return (EINVAL);
1144 1143          }
1145 1144  
1146 1145          /* check key and fix parity if needed */
1147 1146          if (ipsec_check_key(aalg->alg_mech_type, key, B_TRUE,
1148 1147              diagnostic) != 0) {
1149 1148                  mutex_exit(&ipss->ipsec_alg_lock);
1150 1149                  return (EINVAL);
1151 1150          }
1152 1151  
1153 1152          mutex_exit(&ipss->ipsec_alg_lock);
1154 1153  
1155 1154          return (ah_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi,
1156 1155              diagnostic, ahstack));
1157 1156  }
1158 1157  
  
    | 
      ↓ open down ↓ | 
    57 lines elided | 
    
      ↑ open up ↑ | 
  
1159 1158  /* Refactor me */
1160 1159  /*
1161 1160   * Update a security association.  Updates come in two varieties.  The first
1162 1161   * is an update of lifetimes on a non-larval SA.  The second is an update of
1163 1162   * a larval SA, which ends up looking a lot more like an add.
1164 1163   */
1165 1164  static int
1166 1165  ah_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
1167 1166      ipsecah_stack_t *ahstack, uint8_t sadb_msg_type)
1168 1167  {
1169      -        sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
1170 1168          sadb_address_t *dstext =
1171 1169              (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
1172      -        mblk_t  *buf_pkt;
1173      -        int rcode;
1174 1170  
1175 1171          if (dstext == NULL) {
1176 1172                  *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
1177 1173                  return (EINVAL);
1178 1174          }
1179 1175  
1180      -        rcode = sadb_update_sa(mp, ksi, &buf_pkt, &ahstack->ah_sadb,
1181      -            diagnostic, ahstack->ah_pfkey_q, ah_add_sa,
1182      -            ahstack->ipsecah_netstack, sadb_msg_type);
1183      -
1184      -        if ((assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE) ||
1185      -            (rcode != 0)) {
1186      -                return (rcode);
1187      -        }
1188      -
1189      -        HANDLE_BUF_PKT(ah_taskq, ahstack->ipsecah_netstack->netstack_ipsec,
1190      -            ahstack->ah_dropper, buf_pkt);
1191      -
1192      -        return (rcode);
     1176 +        return (sadb_update_sa(mp, ksi, &ahstack->ah_sadb, diagnostic,
     1177 +            ahstack->ah_pfkey_q, ah_add_sa, ahstack->ipsecah_netstack,
     1178 +            sadb_msg_type));
1193 1179  }
1194 1180  
1195 1181  /* Refactor me */
1196 1182  /*
1197 1183   * Delete a security association.  This is REALLY likely to be code common to
1198 1184   * both AH and ESP.  Find the association, then unlink it.
1199 1185   */
1200 1186  static int
1201 1187  ah_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
1202 1188      ipsecah_stack_t *ahstack, uint8_t sadb_msg_type)
1203 1189  {
1204 1190          sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
1205 1191          sadb_address_t *dstext =
1206 1192              (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
1207 1193          sadb_address_t *srcext =
1208 1194              (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
1209 1195          struct sockaddr_in *sin;
1210 1196  
1211 1197          if (assoc == NULL) {
1212 1198                  if (dstext != NULL)
1213 1199                          sin = (struct sockaddr_in *)(dstext + 1);
1214 1200                  else if (srcext != NULL)
1215 1201                          sin = (struct sockaddr_in *)(srcext + 1);
1216 1202                  else {
1217 1203                          *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
1218 1204                          return (EINVAL);
1219 1205                  }
1220 1206                  return (sadb_purge_sa(mp, ksi,
1221 1207                      (sin->sin_family == AF_INET6) ? &ahstack->ah_sadb.s_v6 :
1222 1208                      &ahstack->ah_sadb.s_v4, diagnostic, ahstack->ah_pfkey_q));
1223 1209          }
1224 1210  
1225 1211          return (sadb_delget_sa(mp, ksi, &ahstack->ah_sadb, diagnostic,
1226 1212              ahstack->ah_pfkey_q, sadb_msg_type));
1227 1213  }
1228 1214  
1229 1215  /* Refactor me */
1230 1216  /*
1231 1217   * Convert the entire contents of all of AH's SA tables into PF_KEY SADB_DUMP
1232 1218   * messages.
1233 1219   */
1234 1220  static void
1235 1221  ah_dump(mblk_t *mp, keysock_in_t *ksi, ipsecah_stack_t *ahstack)
1236 1222  {
1237 1223          int error;
1238 1224          sadb_msg_t *samsg;
1239 1225  
1240 1226          /*
1241 1227           * Dump each fanout, bailing if error is non-zero.
1242 1228           */
1243 1229  
1244 1230          error = sadb_dump(ahstack->ah_pfkey_q, mp, ksi, &ahstack->ah_sadb.s_v4);
1245 1231          if (error != 0)
1246 1232                  goto bail;
1247 1233  
1248 1234          error = sadb_dump(ahstack->ah_pfkey_q, mp, ksi, &ahstack->ah_sadb.s_v6);
1249 1235  bail:
1250 1236          ASSERT(mp->b_cont != NULL);
1251 1237          samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
1252 1238          samsg->sadb_msg_errno = (uint8_t)error;
1253 1239          sadb_pfkey_echo(ahstack->ah_pfkey_q, mp,
1254 1240              (sadb_msg_t *)mp->b_cont->b_rptr, ksi, NULL);
1255 1241  }
1256 1242  
1257 1243  /*
1258 1244   * First-cut reality check for an inbound PF_KEY message.
1259 1245   */
1260 1246  static boolean_t
1261 1247  ah_pfkey_reality_failures(mblk_t *mp, keysock_in_t *ksi,
1262 1248      ipsecah_stack_t *ahstack)
1263 1249  {
1264 1250          int diagnostic;
1265 1251  
1266 1252          if (mp->b_cont == NULL) {
1267 1253                  freemsg(mp);
1268 1254                  return (B_TRUE);
1269 1255          }
1270 1256  
1271 1257          if (ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT] != NULL) {
1272 1258                  diagnostic = SADB_X_DIAGNOSTIC_EKEY_PRESENT;
1273 1259                  goto badmsg;
1274 1260          }
1275 1261          if (ksi->ks_in_extv[SADB_EXT_PROPOSAL] != NULL) {
1276 1262                  diagnostic = SADB_X_DIAGNOSTIC_PROP_PRESENT;
1277 1263                  goto badmsg;
1278 1264          }
1279 1265          if (ksi->ks_in_extv[SADB_EXT_SUPPORTED_AUTH] != NULL ||
1280 1266              ksi->ks_in_extv[SADB_EXT_SUPPORTED_ENCRYPT] != NULL) {
1281 1267                  diagnostic = SADB_X_DIAGNOSTIC_SUPP_PRESENT;
1282 1268                  goto badmsg;
1283 1269          }
1284 1270          return (B_FALSE);       /* False ==> no failures */
1285 1271  
1286 1272  badmsg:
1287 1273          sadb_pfkey_error(ahstack->ah_pfkey_q, mp, EINVAL,
1288 1274              diagnostic, ksi->ks_in_serial);
1289 1275          return (B_TRUE);        /* True ==> failures */
1290 1276  }
1291 1277  
1292 1278  /*
1293 1279   * AH parsing of PF_KEY messages.  Keysock did most of the really silly
1294 1280   * error cases.  What I receive is a fully-formed, syntactically legal
1295 1281   * PF_KEY message.  I then need to check semantics...
1296 1282   *
1297 1283   * This code may become common to AH and ESP.  Stay tuned.
1298 1284   *
1299 1285   * I also make the assumption that db_ref's are cool.  If this assumption
1300 1286   * is wrong, this means that someone other than keysock or me has been
1301 1287   * mucking with PF_KEY messages.
1302 1288   */
1303 1289  static void
1304 1290  ah_parse_pfkey(mblk_t *mp, ipsecah_stack_t *ahstack)
1305 1291  {
1306 1292          mblk_t *msg = mp->b_cont;
1307 1293          sadb_msg_t *samsg;
1308 1294          keysock_in_t *ksi;
1309 1295          int error;
1310 1296          int diagnostic = SADB_X_DIAGNOSTIC_NONE;
1311 1297  
1312 1298          ASSERT(msg != NULL);
1313 1299  
1314 1300          samsg = (sadb_msg_t *)msg->b_rptr;
1315 1301          ksi = (keysock_in_t *)mp->b_rptr;
1316 1302  
1317 1303          /*
1318 1304           * If applicable, convert unspecified AF_INET6 to unspecified
1319 1305           * AF_INET.
1320 1306           */
1321 1307          if (!sadb_addrfix(ksi, ahstack->ah_pfkey_q, mp,
1322 1308              ahstack->ipsecah_netstack) ||
1323 1309              ah_pfkey_reality_failures(mp, ksi, ahstack)) {
1324 1310                  return;
1325 1311          }
1326 1312  
1327 1313          switch (samsg->sadb_msg_type) {
1328 1314          case SADB_ADD:
  
    | 
      ↓ open down ↓ | 
    126 lines elided | 
    
      ↑ open up ↑ | 
  
1329 1315                  error = ah_add_sa(mp, ksi, &diagnostic,
1330 1316                      ahstack->ipsecah_netstack);
1331 1317                  if (error != 0) {
1332 1318                          sadb_pfkey_error(ahstack->ah_pfkey_q, mp, error,
1333 1319                              diagnostic, ksi->ks_in_serial);
1334 1320                  }
1335 1321                  /* else ah_add_sa() took care of things. */
1336 1322                  break;
1337 1323          case SADB_DELETE:
1338 1324          case SADB_X_DELPAIR:
1339      -        case SADB_X_DELPAIR_STATE:
1340 1325                  error = ah_del_sa(mp, ksi, &diagnostic, ahstack,
1341 1326                      samsg->sadb_msg_type);
1342 1327                  if (error != 0) {
1343 1328                          sadb_pfkey_error(ahstack->ah_pfkey_q, mp, error,
1344 1329                              diagnostic, ksi->ks_in_serial);
1345 1330                  }
1346 1331                  /* Else ah_del_sa() took care of things. */
1347 1332                  break;
1348 1333          case SADB_GET:
1349 1334                  error = sadb_delget_sa(mp, ksi, &ahstack->ah_sadb, &diagnostic,
1350 1335                      ahstack->ah_pfkey_q, samsg->sadb_msg_type);
1351 1336                  if (error != 0) {
1352 1337                          sadb_pfkey_error(ahstack->ah_pfkey_q, mp, error,
1353 1338                              diagnostic, ksi->ks_in_serial);
1354 1339                  }
1355 1340                  /* Else sadb_get_sa() took care of things. */
1356 1341                  break;
1357 1342          case SADB_FLUSH:
1358 1343                  sadbp_flush(&ahstack->ah_sadb, ahstack->ipsecah_netstack);
1359 1344                  sadb_pfkey_echo(ahstack->ah_pfkey_q, mp, samsg, ksi, NULL);
1360 1345                  break;
1361 1346          case SADB_REGISTER:
1362 1347                  /*
1363 1348                   * Hmmm, let's do it!  Check for extensions (there should
1364 1349                   * be none), extract the fields, call ah_register_out(),
1365 1350                   * then either free or report an error.
1366 1351                   *
1367 1352                   * Keysock takes care of the PF_KEY bookkeeping for this.
1368 1353                   */
1369 1354                  if (ah_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid,
1370 1355                      ksi->ks_in_serial, ahstack, msg_getcred(mp, NULL))) {
1371 1356                          freemsg(mp);
1372 1357                  } else {
1373 1358                          /*
1374 1359                           * Only way this path hits is if there is a memory
1375 1360                           * failure.  It will not return B_FALSE because of
1376 1361                           * lack of ah_pfkey_q if I am in wput().
1377 1362                           */
1378 1363                          sadb_pfkey_error(ahstack->ah_pfkey_q, mp, ENOMEM,
1379 1364                              diagnostic, ksi->ks_in_serial);
1380 1365                  }
1381 1366                  break;
1382 1367          case SADB_UPDATE:
1383 1368          case SADB_X_UPDATEPAIR:
1384 1369                  /*
1385 1370                   * Find a larval, if not there, find a full one and get
1386 1371                   * strict.
1387 1372                   */
1388 1373                  error = ah_update_sa(mp, ksi, &diagnostic, ahstack,
1389 1374                      samsg->sadb_msg_type);
1390 1375                  if (error != 0) {
1391 1376                          sadb_pfkey_error(ahstack->ah_pfkey_q, mp, error,
1392 1377                              diagnostic, ksi->ks_in_serial);
1393 1378                  }
1394 1379                  /* else ah_update_sa() took care of things. */
1395 1380                  break;
1396 1381          case SADB_GETSPI:
1397 1382                  /*
1398 1383                   * Reserve a new larval entry.
1399 1384                   */
1400 1385                  ah_getspi(mp, ksi, ahstack);
1401 1386                  break;
1402 1387          case SADB_ACQUIRE:
1403 1388                  /*
1404 1389                   * Find larval and/or ACQUIRE record and kill it (them), I'm
1405 1390                   * most likely an error.  Inbound ACQUIRE messages should only
1406 1391                   * have the base header.
1407 1392                   */
1408 1393                  sadb_in_acquire(samsg, &ahstack->ah_sadb, ahstack->ah_pfkey_q,
1409 1394                      ahstack->ipsecah_netstack);
1410 1395                  freemsg(mp);
1411 1396                  break;
1412 1397          case SADB_DUMP:
1413 1398                  /*
1414 1399                   * Dump all entries.
1415 1400                   */
1416 1401                  ah_dump(mp, ksi, ahstack);
1417 1402                  /* ah_dump will take care of the return message, etc. */
1418 1403                  break;
1419 1404          case SADB_EXPIRE:
1420 1405                  /* Should never reach me. */
1421 1406                  sadb_pfkey_error(ahstack->ah_pfkey_q, mp, EOPNOTSUPP,
1422 1407                      diagnostic, ksi->ks_in_serial);
1423 1408                  break;
1424 1409          default:
1425 1410                  sadb_pfkey_error(ahstack->ah_pfkey_q, mp, EINVAL,
1426 1411                      SADB_X_DIAGNOSTIC_UNKNOWN_MSG, ksi->ks_in_serial);
1427 1412                  break;
1428 1413          }
1429 1414  }
1430 1415  
1431 1416  /*
1432 1417   * Handle case where PF_KEY says it can't find a keysock for one of my
1433 1418   * ACQUIRE messages.
1434 1419   */
1435 1420  static void
1436 1421  ah_keysock_no_socket(mblk_t *mp, ipsecah_stack_t *ahstack)
1437 1422  {
1438 1423          sadb_msg_t *samsg;
1439 1424          keysock_out_err_t *kse = (keysock_out_err_t *)mp->b_rptr;
1440 1425  
1441 1426          if (mp->b_cont == NULL) {
1442 1427                  freemsg(mp);
1443 1428                  return;
1444 1429          }
1445 1430          samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
1446 1431  
1447 1432          /*
1448 1433           * If keysock can't find any registered, delete the acquire record
1449 1434           * immediately, and handle errors.
1450 1435           */
1451 1436          if (samsg->sadb_msg_type == SADB_ACQUIRE) {
1452 1437                  samsg->sadb_msg_errno = kse->ks_err_errno;
1453 1438                  samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg));
1454 1439                  /*
1455 1440                   * Use the write-side of the ah_pfkey_q
1456 1441                   */
1457 1442                  sadb_in_acquire(samsg, &ahstack->ah_sadb,
1458 1443                      WR(ahstack->ah_pfkey_q), ahstack->ipsecah_netstack);
1459 1444          }
1460 1445  
1461 1446          freemsg(mp);
1462 1447  }
1463 1448  
1464 1449  /*
1465 1450   * AH module write put routine.
1466 1451   */
1467 1452  static void
1468 1453  ipsecah_wput(queue_t *q, mblk_t *mp)
1469 1454  {
1470 1455          ipsec_info_t *ii;
1471 1456          struct iocblk *iocp;
1472 1457          ipsecah_stack_t *ahstack = (ipsecah_stack_t *)q->q_ptr;
1473 1458  
1474 1459          ah3dbg(ahstack, ("In ah_wput().\n"));
1475 1460  
1476 1461          /* NOTE:  Each case must take care of freeing or passing mp. */
1477 1462          switch (mp->b_datap->db_type) {
1478 1463          case M_CTL:
1479 1464                  if ((mp->b_wptr - mp->b_rptr) < sizeof (ipsec_info_t)) {
1480 1465                          /* Not big enough message. */
1481 1466                          freemsg(mp);
1482 1467                          break;
1483 1468                  }
1484 1469                  ii = (ipsec_info_t *)mp->b_rptr;
1485 1470  
1486 1471                  switch (ii->ipsec_info_type) {
1487 1472                  case KEYSOCK_OUT_ERR:
1488 1473                          ah1dbg(ahstack, ("Got KEYSOCK_OUT_ERR message.\n"));
1489 1474                          ah_keysock_no_socket(mp, ahstack);
1490 1475                          break;
1491 1476                  case KEYSOCK_IN:
1492 1477                          AH_BUMP_STAT(ahstack, keysock_in);
1493 1478                          ah3dbg(ahstack, ("Got KEYSOCK_IN message.\n"));
1494 1479  
1495 1480                          /* Parse the message. */
1496 1481                          ah_parse_pfkey(mp, ahstack);
1497 1482                          break;
1498 1483                  case KEYSOCK_HELLO:
1499 1484                          sadb_keysock_hello(&ahstack->ah_pfkey_q, q, mp,
1500 1485                              ah_ager, (void *)ahstack, &ahstack->ah_event,
1501 1486                              SADB_SATYPE_AH);
1502 1487                          break;
1503 1488                  default:
1504 1489                          ah1dbg(ahstack, ("Got M_CTL from above of 0x%x.\n",
1505 1490                              ii->ipsec_info_type));
1506 1491                          freemsg(mp);
1507 1492                          break;
1508 1493                  }
1509 1494                  break;
1510 1495          case M_IOCTL:
1511 1496                  iocp = (struct iocblk *)mp->b_rptr;
1512 1497                  switch (iocp->ioc_cmd) {
1513 1498                  case ND_SET:
1514 1499                  case ND_GET:
1515 1500                          if (nd_getset(q, ahstack->ipsecah_g_nd, mp)) {
1516 1501                                  qreply(q, mp);
1517 1502                                  return;
1518 1503                          } else {
1519 1504                                  iocp->ioc_error = ENOENT;
1520 1505                          }
1521 1506                          /* FALLTHRU */
1522 1507                  default:
1523 1508                          /* We really don't support any other ioctls, do we? */
1524 1509  
1525 1510                          /* Return EINVAL */
1526 1511                          if (iocp->ioc_error != ENOENT)
1527 1512                                  iocp->ioc_error = EINVAL;
1528 1513                          iocp->ioc_count = 0;
1529 1514                          mp->b_datap->db_type = M_IOCACK;
1530 1515                          qreply(q, mp);
1531 1516                          return;
1532 1517                  }
1533 1518          default:
1534 1519                  ah3dbg(ahstack,
1535 1520                      ("Got default message, type %d, passing to IP.\n",
1536 1521                      mp->b_datap->db_type));
1537 1522                  putnext(q, mp);
1538 1523          }
1539 1524  }
1540 1525  
1541 1526  /* Refactor me */
1542 1527  /*
1543 1528   * Updating use times can be tricky business if the ipsa_haspeer flag is
1544 1529   * set.  This function is called once in an SA's lifetime.
1545 1530   *
1546 1531   * Caller has to REFRELE "assoc" which is passed in.  This function has
1547 1532   * to REFRELE any peer SA that is obtained.
1548 1533   */
1549 1534  static void
1550 1535  ah_set_usetime(ipsa_t *assoc, boolean_t inbound)
1551 1536  {
1552 1537          ipsa_t *inassoc, *outassoc;
1553 1538          isaf_t *bucket;
1554 1539          sadb_t *sp;
1555 1540          int outhash;
1556 1541          boolean_t isv6;
1557 1542          netstack_t      *ns = assoc->ipsa_netstack;
1558 1543          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
1559 1544  
1560 1545          /* No peer?  No problem! */
1561 1546          if (!assoc->ipsa_haspeer) {
1562 1547                  sadb_set_usetime(assoc);
1563 1548                  return;
1564 1549          }
1565 1550  
1566 1551          /*
1567 1552           * Otherwise, we want to grab both the original assoc and its peer.
1568 1553           * There might be a race for this, but if it's a real race, the times
1569 1554           * will be out-of-synch by at most a second, and since our time
1570 1555           * granularity is a second, this won't be a problem.
1571 1556           *
1572 1557           * If we need tight synchronization on the peer SA, then we need to
1573 1558           * reconsider.
1574 1559           */
1575 1560  
1576 1561          /* Use address family to select IPv6/IPv4 */
1577 1562          isv6 = (assoc->ipsa_addrfam == AF_INET6);
1578 1563          if (isv6) {
1579 1564                  sp = &ahstack->ah_sadb.s_v6;
1580 1565          } else {
1581 1566                  sp = &ahstack->ah_sadb.s_v4;
1582 1567                  ASSERT(assoc->ipsa_addrfam == AF_INET);
1583 1568          }
1584 1569          if (inbound) {
1585 1570                  inassoc = assoc;
1586 1571                  if (isv6)
1587 1572                          outhash = OUTBOUND_HASH_V6(sp,
1588 1573                              *((in6_addr_t *)&inassoc->ipsa_dstaddr));
1589 1574                  else
1590 1575                          outhash = OUTBOUND_HASH_V4(sp,
1591 1576                              *((ipaddr_t *)&inassoc->ipsa_dstaddr));
1592 1577                  bucket = &sp->sdb_of[outhash];
1593 1578  
1594 1579                  mutex_enter(&bucket->isaf_lock);
1595 1580                  outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi,
1596 1581                      inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr,
1597 1582                      inassoc->ipsa_addrfam);
1598 1583                  mutex_exit(&bucket->isaf_lock);
1599 1584                  if (outassoc == NULL) {
1600 1585                          /* Q: Do we wish to set haspeer == B_FALSE? */
1601 1586                          ah0dbg(("ah_set_usetime: "
1602 1587                              "can't find peer for inbound.\n"));
1603 1588                          sadb_set_usetime(inassoc);
1604 1589                          return;
1605 1590                  }
1606 1591          } else {
1607 1592                  outassoc = assoc;
1608 1593                  bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi);
1609 1594                  mutex_enter(&bucket->isaf_lock);
1610 1595                  inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi,
1611 1596                      outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr,
1612 1597                      outassoc->ipsa_addrfam);
1613 1598                  mutex_exit(&bucket->isaf_lock);
1614 1599                  if (inassoc == NULL) {
1615 1600                          /* Q: Do we wish to set haspeer == B_FALSE? */
1616 1601                          ah0dbg(("ah_set_usetime: "
1617 1602                              "can't find peer for outbound.\n"));
1618 1603                          sadb_set_usetime(outassoc);
1619 1604                          return;
1620 1605                  }
1621 1606          }
1622 1607  
1623 1608          /* Update usetime on both. */
1624 1609          sadb_set_usetime(inassoc);
1625 1610          sadb_set_usetime(outassoc);
1626 1611  
1627 1612          /*
1628 1613           * REFRELE any peer SA.
1629 1614           *
1630 1615           * Because of the multi-line macro nature of IPSA_REFRELE, keep
1631 1616           * them in { }.
1632 1617           */
1633 1618          if (inbound) {
1634 1619                  IPSA_REFRELE(outassoc);
1635 1620          } else {
1636 1621                  IPSA_REFRELE(inassoc);
1637 1622          }
1638 1623  }
1639 1624  
1640 1625  /* Refactor me */
1641 1626  /*
1642 1627   * Add a number of bytes to what the SA has protected so far.  Return
1643 1628   * B_TRUE if the SA can still protect that many bytes.
1644 1629   *
1645 1630   * Caller must REFRELE the passed-in assoc.  This function must REFRELE
1646 1631   * any obtained peer SA.
1647 1632   */
1648 1633  static boolean_t
1649 1634  ah_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound)
1650 1635  {
1651 1636          ipsa_t *inassoc, *outassoc;
1652 1637          isaf_t *bucket;
1653 1638          boolean_t inrc, outrc, isv6;
1654 1639          sadb_t *sp;
1655 1640          int outhash;
1656 1641          netstack_t      *ns = assoc->ipsa_netstack;
1657 1642          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
1658 1643  
1659 1644          /* No peer?  No problem! */
1660 1645          if (!assoc->ipsa_haspeer) {
1661 1646                  return (sadb_age_bytes(ahstack->ah_pfkey_q, assoc, bytes,
1662 1647                      B_TRUE));
1663 1648          }
1664 1649  
1665 1650          /*
1666 1651           * Otherwise, we want to grab both the original assoc and its peer.
1667 1652           * There might be a race for this, but if it's a real race, two
1668 1653           * expire messages may occur.  We limit this by only sending the
1669 1654           * expire message on one of the peers, we'll pick the inbound
1670 1655           * arbitrarily.
1671 1656           *
1672 1657           * If we need tight synchronization on the peer SA, then we need to
1673 1658           * reconsider.
1674 1659           */
1675 1660  
1676 1661          /* Pick v4/v6 bucket based on addrfam. */
1677 1662          isv6 = (assoc->ipsa_addrfam == AF_INET6);
1678 1663          if (isv6) {
1679 1664                  sp = &ahstack->ah_sadb.s_v6;
1680 1665          } else {
1681 1666                  sp = &ahstack->ah_sadb.s_v4;
1682 1667                  ASSERT(assoc->ipsa_addrfam == AF_INET);
1683 1668          }
1684 1669          if (inbound) {
1685 1670                  inassoc = assoc;
1686 1671                  if (isv6)
1687 1672                          outhash = OUTBOUND_HASH_V6(sp,
1688 1673                              *((in6_addr_t *)&inassoc->ipsa_dstaddr));
1689 1674                  else
1690 1675                          outhash = OUTBOUND_HASH_V4(sp,
1691 1676                              *((ipaddr_t *)&inassoc->ipsa_dstaddr));
1692 1677                  bucket = &sp->sdb_of[outhash];
1693 1678                  mutex_enter(&bucket->isaf_lock);
1694 1679                  outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi,
1695 1680                      inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr,
1696 1681                      inassoc->ipsa_addrfam);
1697 1682                  mutex_exit(&bucket->isaf_lock);
1698 1683                  if (outassoc == NULL) {
1699 1684                          /* Q: Do we wish to set haspeer == B_FALSE? */
1700 1685                          ah0dbg(("ah_age_bytes: "
1701 1686                              "can't find peer for inbound.\n"));
1702 1687                          return (sadb_age_bytes(ahstack->ah_pfkey_q, inassoc,
1703 1688                              bytes, B_TRUE));
1704 1689                  }
1705 1690          } else {
1706 1691                  outassoc = assoc;
1707 1692                  bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi);
1708 1693                  mutex_enter(&bucket->isaf_lock);
1709 1694                  inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi,
1710 1695                      outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr,
1711 1696                      outassoc->ipsa_addrfam);
1712 1697                  mutex_exit(&bucket->isaf_lock);
1713 1698                  if (inassoc == NULL) {
1714 1699                          /* Q: Do we wish to set haspeer == B_FALSE? */
1715 1700                          ah0dbg(("ah_age_bytes: "
1716 1701                              "can't find peer for outbound.\n"));
1717 1702                          return (sadb_age_bytes(ahstack->ah_pfkey_q, outassoc,
1718 1703                              bytes, B_TRUE));
1719 1704                  }
1720 1705          }
1721 1706  
1722 1707          inrc = sadb_age_bytes(ahstack->ah_pfkey_q, inassoc, bytes, B_TRUE);
1723 1708          outrc = sadb_age_bytes(ahstack->ah_pfkey_q, outassoc, bytes, B_FALSE);
1724 1709  
1725 1710          /*
1726 1711           * REFRELE any peer SA.
1727 1712           *
1728 1713           * Because of the multi-line macro nature of IPSA_REFRELE, keep
1729 1714           * them in { }.
1730 1715           */
1731 1716          if (inbound) {
1732 1717                  IPSA_REFRELE(outassoc);
1733 1718          } else {
1734 1719                  IPSA_REFRELE(inassoc);
1735 1720          }
1736 1721  
1737 1722          return (inrc && outrc);
1738 1723  }
1739 1724  
1740 1725  /*
1741 1726   * Perform the really difficult work of inserting the proposed situation.
1742 1727   * Called while holding the algorithm lock.
1743 1728   */
1744 1729  static void
1745 1730  ah_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs,
1746 1731      netstack_t *ns)
1747 1732  {
1748 1733          sadb_comb_t *comb = (sadb_comb_t *)(prop + 1);
1749 1734          ipsec_action_t *ap;
1750 1735          ipsec_prot_t *prot;
1751 1736          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
1752 1737          ipsec_stack_t   *ipss = ns->netstack_ipsec;
1753 1738  
1754 1739          ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
1755 1740  
1756 1741          prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
1757 1742          prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t));
1758 1743          *(uint32_t *)(&prop->sadb_prop_replay) = 0;     /* Quick zero-out! */
1759 1744  
1760 1745          prop->sadb_prop_replay = ahstack->ipsecah_replay_size;
1761 1746  
1762 1747          /*
1763 1748           * Based upon algorithm properties, and what-not, prioritize a
1764 1749           * proposal, based on the ordering of the AH algorithms in the
1765 1750           * alternatives in the policy rule or socket that was placed
1766 1751           * in the acquire record.
1767 1752           */
1768 1753  
1769 1754          for (ap = acqrec->ipsacq_act; ap != NULL;
1770 1755              ap = ap->ipa_next) {
1771 1756                  ipsec_alginfo_t *aalg;
1772 1757  
1773 1758                  if ((ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY) ||
1774 1759                      (!ap->ipa_act.ipa_apply.ipp_use_ah))
1775 1760                          continue;
1776 1761  
1777 1762                  prot = &ap->ipa_act.ipa_apply;
1778 1763  
1779 1764                  ASSERT(prot->ipp_auth_alg > 0);
1780 1765  
1781 1766                  aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
1782 1767                      [prot->ipp_auth_alg];
1783 1768                  if (aalg == NULL || !ALG_VALID(aalg))
1784 1769                          continue;
1785 1770  
1786 1771                  /* XXX check aalg for duplicates??.. */
1787 1772  
1788 1773                  comb->sadb_comb_flags = 0;
1789 1774                  comb->sadb_comb_reserved = 0;
1790 1775                  comb->sadb_comb_encrypt = 0;
1791 1776                  comb->sadb_comb_encrypt_minbits = 0;
1792 1777                  comb->sadb_comb_encrypt_maxbits = 0;
1793 1778  
1794 1779                  comb->sadb_comb_auth = aalg->alg_id;
1795 1780                  comb->sadb_comb_auth_minbits =
1796 1781                      MAX(prot->ipp_ah_minbits, aalg->alg_ef_minbits);
1797 1782                  comb->sadb_comb_auth_maxbits =
1798 1783                      MIN(prot->ipp_ah_maxbits, aalg->alg_ef_maxbits);
1799 1784  
1800 1785                  /*
1801 1786                   * The following may be based on algorithm
1802 1787                   * properties, but in the meantime, we just pick
1803 1788                   * some good, sensible numbers.  Key mgmt. can
1804 1789                   * (and perhaps should) be the place to finalize
1805 1790                   * such decisions.
1806 1791                   */
1807 1792  
1808 1793                  /*
1809 1794                   * No limits on allocations, since we really don't
1810 1795                   * support that concept currently.
1811 1796                   */
1812 1797                  comb->sadb_comb_soft_allocations = 0;
1813 1798                  comb->sadb_comb_hard_allocations = 0;
1814 1799  
1815 1800                  /*
1816 1801                   * These may want to come from policy rule..
1817 1802                   */
1818 1803                  comb->sadb_comb_soft_bytes =
1819 1804                      ahstack->ipsecah_default_soft_bytes;
1820 1805                  comb->sadb_comb_hard_bytes =
1821 1806                      ahstack->ipsecah_default_hard_bytes;
1822 1807                  comb->sadb_comb_soft_addtime =
1823 1808                      ahstack->ipsecah_default_soft_addtime;
1824 1809                  comb->sadb_comb_hard_addtime =
1825 1810                      ahstack->ipsecah_default_hard_addtime;
1826 1811                  comb->sadb_comb_soft_usetime =
1827 1812                      ahstack->ipsecah_default_soft_usetime;
1828 1813                  comb->sadb_comb_hard_usetime =
1829 1814                      ahstack->ipsecah_default_hard_usetime;
1830 1815  
1831 1816                  prop->sadb_prop_len += SADB_8TO64(sizeof (*comb));
1832 1817                  if (--combs == 0)
1833 1818                          return; /* out of space.. */
1834 1819                  comb++;
1835 1820          }
1836 1821  }
1837 1822  
1838 1823  /*
1839 1824   * Prepare and actually send the SADB_ACQUIRE message to PF_KEY.
1840 1825   */
1841 1826  static void
1842 1827  ah_send_acquire(ipsacq_t *acqrec, mblk_t *extended, netstack_t *ns)
1843 1828  {
1844 1829          uint_t combs;
1845 1830          sadb_msg_t *samsg;
1846 1831          sadb_prop_t *prop;
1847 1832          mblk_t *pfkeymp, *msgmp;
1848 1833          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
1849 1834          ipsec_stack_t   *ipss = ns->netstack_ipsec;
1850 1835  
1851 1836          AH_BUMP_STAT(ahstack, acquire_requests);
1852 1837  
1853 1838          if (ahstack->ah_pfkey_q == NULL) {
1854 1839                  mutex_exit(&acqrec->ipsacq_lock);
1855 1840                  return;
1856 1841          }
1857 1842  
1858 1843          /* Set up ACQUIRE. */
1859 1844          pfkeymp = sadb_setup_acquire(acqrec, SADB_SATYPE_AH,
1860 1845              ns->netstack_ipsec);
1861 1846          if (pfkeymp == NULL) {
1862 1847                  ah0dbg(("sadb_setup_acquire failed.\n"));
1863 1848                  mutex_exit(&acqrec->ipsacq_lock);
1864 1849                  return;
1865 1850          }
1866 1851          ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
1867 1852          combs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
1868 1853          msgmp = pfkeymp->b_cont;
1869 1854          samsg = (sadb_msg_t *)(msgmp->b_rptr);
1870 1855  
1871 1856          /* Insert proposal here. */
1872 1857  
1873 1858          prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len);
1874 1859          ah_insert_prop(prop, acqrec, combs, ns);
1875 1860          samsg->sadb_msg_len += prop->sadb_prop_len;
1876 1861          msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len);
1877 1862  
1878 1863          mutex_exit(&ipss->ipsec_alg_lock);
1879 1864  
1880 1865          /*
1881 1866           * Must mutex_exit() before sending PF_KEY message up, in
1882 1867           * order to avoid recursive mutex_enter() if there are no registered
1883 1868           * listeners.
1884 1869           *
1885 1870           * Once I've sent the message, I'm cool anyway.
1886 1871           */
1887 1872          mutex_exit(&acqrec->ipsacq_lock);
1888 1873          if (extended != NULL) {
1889 1874                  putnext(ahstack->ah_pfkey_q, extended);
1890 1875          }
1891 1876          putnext(ahstack->ah_pfkey_q, pfkeymp);
1892 1877  }
1893 1878  
1894 1879  /* Refactor me */
1895 1880  /*
1896 1881   * Handle the SADB_GETSPI message.  Create a larval SA.
1897 1882   */
1898 1883  static void
1899 1884  ah_getspi(mblk_t *mp, keysock_in_t *ksi, ipsecah_stack_t *ahstack)
1900 1885  {
1901 1886          ipsa_t *newbie, *target;
1902 1887          isaf_t *outbound, *inbound;
  
    | 
      ↓ open down ↓ | 
    553 lines elided | 
    
      ↑ open up ↑ | 
  
1903 1888          int rc, diagnostic;
1904 1889          sadb_sa_t *assoc;
1905 1890          keysock_out_t *kso;
1906 1891          uint32_t newspi;
1907 1892  
1908 1893          /*
1909 1894           * Randomly generate a proposed SPI value.
1910 1895           */
1911 1896          (void) random_get_pseudo_bytes((uint8_t *)&newspi, sizeof (uint32_t));
1912 1897          newbie = sadb_getspi(ksi, newspi, &diagnostic,
1913      -            ahstack->ipsecah_netstack, IPPROTO_AH);
     1898 +            ahstack->ipsecah_netstack);
1914 1899  
1915 1900          if (newbie == NULL) {
1916 1901                  sadb_pfkey_error(ahstack->ah_pfkey_q, mp, ENOMEM, diagnostic,
1917 1902                      ksi->ks_in_serial);
1918 1903                  return;
1919 1904          } else if (newbie == (ipsa_t *)-1) {
1920 1905                  sadb_pfkey_error(ahstack->ah_pfkey_q, mp, EINVAL, diagnostic,
1921 1906                      ksi->ks_in_serial);
1922 1907                  return;
1923 1908          }
1924 1909  
1925 1910          /*
1926 1911           * XXX - We may randomly collide.  We really should recover from this.
1927 1912           *       Unfortunately, that could require spending way-too-much-time
1928 1913           *       in here.  For now, let the user retry.
1929 1914           */
1930 1915  
1931 1916          if (newbie->ipsa_addrfam == AF_INET6) {
1932 1917                  outbound = OUTBOUND_BUCKET_V6(&ahstack->ah_sadb.s_v6,
1933 1918                      *(uint32_t *)(newbie->ipsa_dstaddr));
1934 1919                  inbound = INBOUND_BUCKET(&ahstack->ah_sadb.s_v6,
1935 1920                      newbie->ipsa_spi);
1936 1921          } else {
1937 1922                  outbound = OUTBOUND_BUCKET_V4(&ahstack->ah_sadb.s_v4,
1938 1923                      *(uint32_t *)(newbie->ipsa_dstaddr));
1939 1924                  inbound = INBOUND_BUCKET(&ahstack->ah_sadb.s_v4,
1940 1925                      newbie->ipsa_spi);
1941 1926          }
1942 1927  
1943 1928          mutex_enter(&outbound->isaf_lock);
1944 1929          mutex_enter(&inbound->isaf_lock);
1945 1930  
1946 1931          /*
1947 1932           * Check for collisions (i.e. did sadb_getspi() return with something
1948 1933           * that already exists?).
1949 1934           *
1950 1935           * Try outbound first.  Even though SADB_GETSPI is traditionally
1951 1936           * for inbound SAs, you never know what a user might do.
1952 1937           */
1953 1938          target = ipsec_getassocbyspi(outbound, newbie->ipsa_spi,
1954 1939              newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, newbie->ipsa_addrfam);
1955 1940          if (target == NULL) {
1956 1941                  target = ipsec_getassocbyspi(inbound, newbie->ipsa_spi,
1957 1942                      newbie->ipsa_srcaddr, newbie->ipsa_dstaddr,
1958 1943                      newbie->ipsa_addrfam);
1959 1944          }
1960 1945  
1961 1946          /*
1962 1947           * I don't have collisions elsewhere!
1963 1948           * (Nor will I because I'm still holding inbound/outbound locks.)
1964 1949           */
1965 1950  
1966 1951          if (target != NULL) {
1967 1952                  rc = EEXIST;
1968 1953                  IPSA_REFRELE(target);
1969 1954          } else {
1970 1955                  /*
1971 1956                   * sadb_insertassoc() also checks for collisions, so
1972 1957                   * if there's a colliding larval entry, rc will be set
1973 1958                   * to EEXIST.
1974 1959                   */
1975 1960                  rc = sadb_insertassoc(newbie, inbound);
1976 1961                  newbie->ipsa_hardexpiretime = gethrestime_sec();
1977 1962                  newbie->ipsa_hardexpiretime += ahstack->ipsecah_larval_timeout;
1978 1963          }
1979 1964  
1980 1965          /*
1981 1966           * Can exit outbound mutex.  Hold inbound until we're done with
1982 1967           * newbie.
1983 1968           */
1984 1969          mutex_exit(&outbound->isaf_lock);
1985 1970  
1986 1971          if (rc != 0) {
1987 1972                  mutex_exit(&inbound->isaf_lock);
1988 1973                  IPSA_REFRELE(newbie);
1989 1974                  sadb_pfkey_error(ahstack->ah_pfkey_q, mp, rc,
1990 1975                      SADB_X_DIAGNOSTIC_NONE, ksi->ks_in_serial);
1991 1976                  return;
1992 1977          }
1993 1978  
1994 1979          /* Can write here because I'm still holding the bucket lock. */
1995 1980          newbie->ipsa_type = SADB_SATYPE_AH;
1996 1981  
1997 1982          /*
1998 1983           * Construct successful return message.  We have one thing going
1999 1984           * for us in PF_KEY v2.  That's the fact that
2000 1985           *      sizeof (sadb_spirange_t) == sizeof (sadb_sa_t)
2001 1986           */
2002 1987          assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE];
2003 1988          assoc->sadb_sa_exttype = SADB_EXT_SA;
2004 1989          assoc->sadb_sa_spi = newbie->ipsa_spi;
2005 1990          *((uint64_t *)(&assoc->sadb_sa_replay)) = 0;
2006 1991          mutex_exit(&inbound->isaf_lock);
2007 1992  
2008 1993          /* Convert KEYSOCK_IN to KEYSOCK_OUT. */
2009 1994          kso = (keysock_out_t *)ksi;
2010 1995          kso->ks_out_len = sizeof (*kso);
2011 1996          kso->ks_out_serial = ksi->ks_in_serial;
2012 1997          kso->ks_out_type = KEYSOCK_OUT;
2013 1998  
2014 1999          /*
2015 2000           * Can safely putnext() to ah_pfkey_q, because this is a turnaround
2016 2001           * from the ah_pfkey_q.
2017 2002           */
2018 2003          putnext(ahstack->ah_pfkey_q, mp);
2019 2004  }
2020 2005  
2021 2006  /*
2022 2007   * IPv6 sends up the ICMP errors for validation and the removal of the AH
2023 2008   * header.
2024 2009   * If succesful, the mp has been modified to not include the AH header so
2025 2010   * that the caller can fanout to the ULP's icmp error handler.
2026 2011   */
2027 2012  static mblk_t *
2028 2013  ah_icmp_error_v6(mblk_t *mp, ip_recv_attr_t *ira, ipsecah_stack_t *ahstack)
2029 2014  {
2030 2015          ip6_t *ip6h, *oip6h;
2031 2016          uint16_t hdr_length, ah_length;
2032 2017          uint8_t *nexthdrp;
2033 2018          ah_t *ah;
2034 2019          icmp6_t *icmp6;
2035 2020          isaf_t *isaf;
2036 2021          ipsa_t *assoc;
2037 2022          uint8_t *post_ah_ptr;
2038 2023          ipsec_stack_t   *ipss = ahstack->ipsecah_netstack->netstack_ipsec;
2039 2024  
2040 2025          /*
2041 2026           * Eat the cost of a pullupmsg() for now.  It makes the rest of this
2042 2027           * code far less convoluted.
2043 2028           */
2044 2029          if (!pullupmsg(mp, -1) ||
2045 2030              !ip_hdr_length_nexthdr_v6(mp, (ip6_t *)mp->b_rptr, &hdr_length,
2046 2031              &nexthdrp) ||
2047 2032              mp->b_rptr + hdr_length + sizeof (icmp6_t) + sizeof (ip6_t) +
2048 2033              sizeof (ah_t) > mp->b_wptr) {
2049 2034                  IP_AH_BUMP_STAT(ipss, in_discards);
2050 2035                  ip_drop_packet(mp, B_TRUE, ira->ira_ill,
2051 2036                      DROPPER(ipss, ipds_ah_nomem),
2052 2037                      &ahstack->ah_dropper);
2053 2038                  return (NULL);
2054 2039          }
2055 2040  
2056 2041          oip6h = (ip6_t *)mp->b_rptr;
2057 2042          icmp6 = (icmp6_t *)((uint8_t *)oip6h + hdr_length);
2058 2043          ip6h = (ip6_t *)(icmp6 + 1);
2059 2044          if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_length, &nexthdrp)) {
2060 2045                  IP_AH_BUMP_STAT(ipss, in_discards);
2061 2046                  ip_drop_packet(mp, B_TRUE, ira->ira_ill,
2062 2047                      DROPPER(ipss, ipds_ah_bad_v6_hdrs),
2063 2048                      &ahstack->ah_dropper);
2064 2049                  return (NULL);
2065 2050          }
2066 2051          ah = (ah_t *)((uint8_t *)ip6h + hdr_length);
2067 2052  
2068 2053          isaf = OUTBOUND_BUCKET_V6(&ahstack->ah_sadb.s_v6, ip6h->ip6_dst);
2069 2054          mutex_enter(&isaf->isaf_lock);
2070 2055          assoc = ipsec_getassocbyspi(isaf, ah->ah_spi,
2071 2056              (uint32_t *)&ip6h->ip6_src, (uint32_t *)&ip6h->ip6_dst, AF_INET6);
2072 2057          mutex_exit(&isaf->isaf_lock);
2073 2058  
2074 2059          if (assoc == NULL) {
2075 2060                  IP_AH_BUMP_STAT(ipss, lookup_failure);
2076 2061                  IP_AH_BUMP_STAT(ipss, in_discards);
2077 2062                  if (ahstack->ipsecah_log_unknown_spi) {
2078 2063                          ipsec_assocfailure(info.mi_idnum, 0, 0,
2079 2064                              SL_CONSOLE | SL_WARN | SL_ERROR,
2080 2065                              "Bad ICMP message - No association for the "
2081 2066                              "attached AH header whose spi is 0x%x, "
2082 2067                              "sender is 0x%x\n",
2083 2068                              ah->ah_spi, &oip6h->ip6_src, AF_INET6,
2084 2069                              ahstack->ipsecah_netstack);
2085 2070                  }
2086 2071                  ip_drop_packet(mp, B_TRUE, ira->ira_ill,
2087 2072                      DROPPER(ipss, ipds_ah_no_sa),
2088 2073                      &ahstack->ah_dropper);
2089 2074                  return (NULL);
2090 2075          }
2091 2076  
2092 2077          IPSA_REFRELE(assoc);
2093 2078  
2094 2079          /*
2095 2080           * There seems to be a valid association. If there is enough of AH
2096 2081           * header remove it, otherwise bail.  One could check whether it has
2097 2082           * complete AH header plus 8 bytes but it does not make sense if an
2098 2083           * icmp error is returned for ICMP messages e.g ICMP time exceeded,
2099 2084           * that are being sent up. Let the caller figure out.
2100 2085           *
2101 2086           * NOTE: ah_length is the number of 32 bit words minus 2.
2102 2087           */
2103 2088          ah_length = (ah->ah_length << 2) + 8;
2104 2089          post_ah_ptr = (uint8_t *)ah + ah_length;
2105 2090  
2106 2091          if (post_ah_ptr > mp->b_wptr) {
2107 2092                  IP_AH_BUMP_STAT(ipss, in_discards);
2108 2093                  ip_drop_packet(mp, B_TRUE, ira->ira_ill,
2109 2094                      DROPPER(ipss, ipds_ah_bad_length),
2110 2095                      &ahstack->ah_dropper);
2111 2096                  return (NULL);
2112 2097          }
2113 2098  
2114 2099          ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - ah_length);
2115 2100          *nexthdrp = ah->ah_nexthdr;
2116 2101          ovbcopy(post_ah_ptr, ah,
2117 2102              (size_t)((uintptr_t)mp->b_wptr - (uintptr_t)post_ah_ptr));
2118 2103          mp->b_wptr -= ah_length;
2119 2104  
2120 2105          return (mp);
2121 2106  }
2122 2107  
2123 2108  /*
2124 2109   * IP sends up the ICMP errors for validation and the removal of
2125 2110   * the AH header.
2126 2111   * If succesful, the mp has been modified to not include the AH header so
2127 2112   * that the caller can fanout to the ULP's icmp error handler.
2128 2113   */
2129 2114  static mblk_t *
2130 2115  ah_icmp_error_v4(mblk_t *mp, ip_recv_attr_t *ira, ipsecah_stack_t *ahstack)
2131 2116  {
2132 2117          mblk_t *mp1;
2133 2118          icmph_t *icmph;
2134 2119          int iph_hdr_length;
2135 2120          int hdr_length;
2136 2121          isaf_t *hptr;
2137 2122          ipsa_t *assoc;
2138 2123          int ah_length;
2139 2124          ipha_t *ipha;
2140 2125          ipha_t *oipha;
2141 2126          ah_t *ah;
2142 2127          uint32_t length;
2143 2128          int alloc_size;
2144 2129          uint8_t nexthdr;
2145 2130          ipsec_stack_t   *ipss = ahstack->ipsecah_netstack->netstack_ipsec;
2146 2131  
2147 2132          oipha = ipha = (ipha_t *)mp->b_rptr;
2148 2133          iph_hdr_length = IPH_HDR_LENGTH(ipha);
2149 2134          icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length];
2150 2135  
2151 2136          ipha = (ipha_t *)&icmph[1];
2152 2137          hdr_length = IPH_HDR_LENGTH(ipha);
2153 2138  
2154 2139          /*
2155 2140           * See if we have enough to locate the SPI
2156 2141           */
2157 2142          if ((uchar_t *)ipha + hdr_length + 8 > mp->b_wptr) {
2158 2143                  if (!pullupmsg(mp, (uchar_t *)ipha + hdr_length + 8 -
2159 2144                      mp->b_rptr)) {
2160 2145                          ipsec_rl_strlog(ahstack->ipsecah_netstack,
2161 2146                              info.mi_idnum, 0, 0,
2162 2147                              SL_WARN | SL_ERROR,
2163 2148                              "ICMP error: Small AH header\n");
2164 2149                          IP_AH_BUMP_STAT(ipss, in_discards);
2165 2150                          ip_drop_packet(mp, B_TRUE, ira->ira_ill,
2166 2151                              DROPPER(ipss, ipds_ah_bad_length),
2167 2152                              &ahstack->ah_dropper);
2168 2153                          return (NULL);
2169 2154                  }
2170 2155                  icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length];
2171 2156                  ipha = (ipha_t *)&icmph[1];
2172 2157          }
2173 2158  
2174 2159          ah = (ah_t *)((uint8_t *)ipha + hdr_length);
2175 2160          nexthdr = ah->ah_nexthdr;
2176 2161  
2177 2162          hptr = OUTBOUND_BUCKET_V4(&ahstack->ah_sadb.s_v4, ipha->ipha_dst);
2178 2163          mutex_enter(&hptr->isaf_lock);
2179 2164          assoc = ipsec_getassocbyspi(hptr, ah->ah_spi,
2180 2165              (uint32_t *)&ipha->ipha_src, (uint32_t *)&ipha->ipha_dst, AF_INET);
2181 2166          mutex_exit(&hptr->isaf_lock);
2182 2167  
2183 2168          if (assoc == NULL) {
2184 2169                  IP_AH_BUMP_STAT(ipss, lookup_failure);
2185 2170                  IP_AH_BUMP_STAT(ipss, in_discards);
2186 2171                  if (ahstack->ipsecah_log_unknown_spi) {
2187 2172                          ipsec_assocfailure(info.mi_idnum, 0, 0,
2188 2173                              SL_CONSOLE | SL_WARN | SL_ERROR,
2189 2174                              "Bad ICMP message - No association for the "
2190 2175                              "attached AH header whose spi is 0x%x, "
2191 2176                              "sender is 0x%x\n",
2192 2177                              ah->ah_spi, &oipha->ipha_src, AF_INET,
2193 2178                              ahstack->ipsecah_netstack);
2194 2179                  }
2195 2180                  ip_drop_packet(mp, B_TRUE, ira->ira_ill,
2196 2181                      DROPPER(ipss, ipds_ah_no_sa),
2197 2182                      &ahstack->ah_dropper);
2198 2183                  return (NULL);
2199 2184          }
2200 2185  
2201 2186          IPSA_REFRELE(assoc);
2202 2187          /*
2203 2188           * There seems to be a valid association. If there
2204 2189           * is enough of AH header remove it, otherwise remove
2205 2190           * as much as possible and send it back. One could check
2206 2191           * whether it has complete AH header plus 8 bytes but it
2207 2192           * does not make sense if an icmp error is returned for
2208 2193           * ICMP messages e.g ICMP time exceeded, that are being
2209 2194           * sent up. Let the caller figure out.
2210 2195           *
2211 2196           * NOTE: ah_length is the number of 32 bit words minus 2.
2212 2197           */
2213 2198          ah_length = (ah->ah_length << 2) + 8;
2214 2199  
2215 2200          if ((uchar_t *)ipha + hdr_length + ah_length > mp->b_wptr) {
2216 2201                  if (mp->b_cont == NULL) {
2217 2202                          /*
2218 2203                           * There is nothing to pullup. Just remove as
2219 2204                           * much as possible. This is a common case for
2220 2205                           * IPV4.
2221 2206                           */
2222 2207                          ah_length = (mp->b_wptr - ((uchar_t *)ipha +
2223 2208                              hdr_length));
2224 2209                          goto done;
2225 2210                  }
2226 2211                  /* Pullup the full ah header */
2227 2212                  if (!pullupmsg(mp, (uchar_t *)ah + ah_length - mp->b_rptr)) {
2228 2213                          /*
2229 2214                           * pullupmsg could have failed if there was not
2230 2215                           * enough to pullup or memory allocation failed.
2231 2216                           * We tried hard, give up now.
2232 2217                           */
2233 2218                          IP_AH_BUMP_STAT(ipss, in_discards);
2234 2219                          ip_drop_packet(mp, B_TRUE, ira->ira_ill,
2235 2220                              DROPPER(ipss, ipds_ah_nomem),
2236 2221                              &ahstack->ah_dropper);
2237 2222                          return (NULL);
2238 2223                  }
2239 2224                  icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length];
2240 2225                  ipha = (ipha_t *)&icmph[1];
2241 2226          }
2242 2227  done:
2243 2228          /*
2244 2229           * Remove the AH header and change the protocol.
2245 2230           * Don't update the spi fields in the ip_recv_attr_t
2246 2231           * as we are called just to validate the
2247 2232           * message attached to the ICMP message.
2248 2233           *
2249 2234           * If we never pulled up since all of the message
2250 2235           * is in one single mblk, we can't remove the AH header
2251 2236           * by just setting the b_wptr to the beginning of the
2252 2237           * AH header. We need to allocate a mblk that can hold
2253 2238           * up until the inner IP header and copy them.
2254 2239           */
2255 2240          alloc_size = iph_hdr_length + sizeof (icmph_t) + hdr_length;
2256 2241  
2257 2242          if ((mp1 = allocb(alloc_size, BPRI_LO)) == NULL) {
2258 2243                  IP_AH_BUMP_STAT(ipss, in_discards);
2259 2244                  ip_drop_packet(mp, B_TRUE, ira->ira_ill,
2260 2245                      DROPPER(ipss, ipds_ah_nomem),
2261 2246                      &ahstack->ah_dropper);
2262 2247                  return (NULL);
2263 2248          }
2264 2249          bcopy(mp->b_rptr, mp1->b_rptr, alloc_size);
2265 2250          mp1->b_wptr += alloc_size;
2266 2251  
2267 2252          /*
2268 2253           * Skip whatever we have copied and as much of AH header
2269 2254           * possible. If we still have something left in the original
2270 2255           * message, tag on.
2271 2256           */
2272 2257          mp->b_rptr = (uchar_t *)ipha + hdr_length + ah_length;
2273 2258  
2274 2259          if (mp->b_rptr != mp->b_wptr) {
2275 2260                  mp1->b_cont = mp;
2276 2261          } else {
2277 2262                  if (mp->b_cont != NULL)
2278 2263                          mp1->b_cont = mp->b_cont;
2279 2264                  freeb(mp);
2280 2265          }
2281 2266  
2282 2267          ipha = (ipha_t *)(mp1->b_rptr + iph_hdr_length + sizeof (icmph_t));
2283 2268          ipha->ipha_protocol = nexthdr;
2284 2269          length = ntohs(ipha->ipha_length);
2285 2270          length -= ah_length;
2286 2271          ipha->ipha_length = htons((uint16_t)length);
2287 2272          ipha->ipha_hdr_checksum = 0;
2288 2273          ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha);
2289 2274  
2290 2275          return (mp1);
2291 2276  }
2292 2277  
2293 2278  /*
2294 2279   * IP calls this to validate the ICMP errors that
2295 2280   * we got from the network.
2296 2281   */
2297 2282  mblk_t *
2298 2283  ipsecah_icmp_error(mblk_t *data_mp, ip_recv_attr_t *ira)
2299 2284  {
2300 2285          netstack_t      *ns = ira->ira_ill->ill_ipst->ips_netstack;
2301 2286          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
2302 2287  
2303 2288          if (ira->ira_flags & IRAF_IS_IPV4)
2304 2289                  return (ah_icmp_error_v4(data_mp, ira, ahstack));
2305 2290          else
2306 2291                  return (ah_icmp_error_v6(data_mp, ira, ahstack));
2307 2292  }
2308 2293  
2309 2294  static int
2310 2295  ah_fix_tlv_options_v6(uint8_t *oi_opt, uint8_t *pi_opt, uint_t ehdrlen,
2311 2296      uint8_t hdr_type, boolean_t copy_always)
2312 2297  {
2313 2298          uint8_t opt_type;
2314 2299          uint_t optlen;
2315 2300  
2316 2301          ASSERT(hdr_type == IPPROTO_DSTOPTS || hdr_type == IPPROTO_HOPOPTS);
2317 2302  
2318 2303          /*
2319 2304           * Copy the next header and hdr ext. len of the HOP-by-HOP
2320 2305           * and Destination option.
2321 2306           */
2322 2307          *pi_opt++ = *oi_opt++;
2323 2308          *pi_opt++ = *oi_opt++;
2324 2309          ehdrlen -= 2;
2325 2310  
2326 2311          /*
2327 2312           * Now handle all the TLV encoded options.
2328 2313           */
2329 2314          while (ehdrlen != 0) {
2330 2315                  opt_type = *oi_opt;
2331 2316  
2332 2317                  if (opt_type == IP6OPT_PAD1) {
2333 2318                          optlen = 1;
2334 2319                  } else {
2335 2320                          if (ehdrlen < 2)
2336 2321                                  goto bad_opt;
2337 2322                          optlen = 2 + oi_opt[1];
2338 2323                          if (optlen > ehdrlen)
2339 2324                                  goto bad_opt;
2340 2325                  }
2341 2326                  if (copy_always || !(opt_type & IP6OPT_MUTABLE)) {
2342 2327                          bcopy(oi_opt, pi_opt, optlen);
2343 2328                  } else {
2344 2329                          if (optlen == 1) {
2345 2330                                  *pi_opt = 0;
2346 2331                          } else {
2347 2332                                  /*
2348 2333                                   * Copy the type and data length fields.
2349 2334                                   * Zero the option data by skipping
2350 2335                                   * option type and option data len
2351 2336                                   * fields.
2352 2337                                   */
2353 2338                                  *pi_opt = *oi_opt;
2354 2339                                  *(pi_opt + 1) = *(oi_opt + 1);
2355 2340                                  bzero(pi_opt + 2, optlen - 2);
2356 2341                          }
2357 2342                  }
2358 2343                  ehdrlen -= optlen;
2359 2344                  oi_opt += optlen;
2360 2345                  pi_opt += optlen;
2361 2346          }
2362 2347          return (0);
2363 2348  bad_opt:
2364 2349          return (-1);
2365 2350  }
2366 2351  
2367 2352  /*
2368 2353   * Construct a pseudo header for AH, processing all the options.
2369 2354   *
2370 2355   * oip6h is the IPv6 header of the incoming or outgoing packet.
2371 2356   * ip6h is the pointer to the pseudo headers IPV6 header. All
2372 2357   * the space needed for the options have been allocated including
2373 2358   * the AH header.
2374 2359   *
2375 2360   * If copy_always is set, all the options that appear before AH are copied
2376 2361   * blindly without checking for IP6OPT_MUTABLE. This is used by
2377 2362   * ah_auth_out_done().  Please refer to that function for details.
2378 2363   *
2379 2364   * NOTE :
2380 2365   *
2381 2366   * *  AH header is never copied in this function even if copy_always
2382 2367   *    is set. It just returns the ah_offset - offset of the AH header
2383 2368   *    and the caller needs to do the copying. This is done so that we
2384 2369   *    don't have pass extra arguments e.g. SA etc. and also,
2385 2370   *    it is not needed when ah_auth_out_done is calling this function.
2386 2371   */
2387 2372  static uint_t
2388 2373  ah_fix_phdr_v6(ip6_t *ip6h, ip6_t *oip6h, boolean_t outbound,
2389 2374      boolean_t copy_always)
2390 2375  {
2391 2376          uint8_t *oi_opt;
2392 2377          uint8_t *pi_opt;
2393 2378          uint8_t nexthdr;
2394 2379          uint8_t *prev_nexthdr;
2395 2380          ip6_hbh_t *hbhhdr;
2396 2381          ip6_dest_t *dsthdr = NULL;
2397 2382          ip6_rthdr0_t *rthdr;
2398 2383          int ehdrlen;
2399 2384          ah_t *ah;
2400 2385          int ret;
2401 2386  
2402 2387          /*
2403 2388           * In the outbound case for source route, ULP has already moved
2404 2389           * the first hop, which is now in ip6_dst. We need to re-arrange
2405 2390           * the header to make it look like how it would appear in the
2406 2391           * receiver i.e
2407 2392           *
2408 2393           * Because of ip_massage_options_v6 the header looks like
2409 2394           * this :
2410 2395           *
2411 2396           * ip6_src = S, ip6_dst = I1. followed by I2,I3,D.
2412 2397           *
2413 2398           * When it reaches the receiver, it would look like
2414 2399           *
2415 2400           * ip6_src = S, ip6_dst = D. followed by I1,I2,I3.
2416 2401           *
2417 2402           * NOTE : We assume that there are no problems with the options
2418 2403           * as IP should have already checked this.
2419 2404           */
2420 2405  
2421 2406          oi_opt = (uchar_t *)&oip6h[1];
2422 2407          pi_opt = (uchar_t *)&ip6h[1];
2423 2408  
2424 2409          /*
2425 2410           * We set the prev_nexthdr properly in the pseudo header.
2426 2411           * After we finish authentication and come back from the
2427 2412           * algorithm module, pseudo header will become the real
2428 2413           * IP header.
2429 2414           */
2430 2415          prev_nexthdr = (uint8_t *)&ip6h->ip6_nxt;
2431 2416          nexthdr = oip6h->ip6_nxt;
2432 2417          /* Assume IP has already stripped it */
2433 2418          ASSERT(nexthdr != IPPROTO_FRAGMENT);
2434 2419          ah = NULL;
2435 2420          dsthdr = NULL;
2436 2421          for (;;) {
2437 2422                  switch (nexthdr) {
2438 2423                  case IPPROTO_HOPOPTS:
2439 2424                          hbhhdr = (ip6_hbh_t *)oi_opt;
2440 2425                          nexthdr = hbhhdr->ip6h_nxt;
2441 2426                          ehdrlen = 8 * (hbhhdr->ip6h_len + 1);
2442 2427                          ret = ah_fix_tlv_options_v6(oi_opt, pi_opt, ehdrlen,
2443 2428                              IPPROTO_HOPOPTS, copy_always);
2444 2429                          /*
2445 2430                           * Return a zero offset indicating error if there
2446 2431                           * was error.
2447 2432                           */
2448 2433                          if (ret == -1)
2449 2434                                  return (0);
2450 2435                          hbhhdr = (ip6_hbh_t *)pi_opt;
2451 2436                          prev_nexthdr = (uint8_t *)&hbhhdr->ip6h_nxt;
2452 2437                          break;
2453 2438                  case IPPROTO_ROUTING:
2454 2439                          rthdr = (ip6_rthdr0_t *)oi_opt;
2455 2440                          nexthdr = rthdr->ip6r0_nxt;
2456 2441                          ehdrlen = 8 * (rthdr->ip6r0_len + 1);
2457 2442                          if (!copy_always && outbound) {
2458 2443                                  int i, left;
2459 2444                                  ip6_rthdr0_t *prthdr;
2460 2445                                  in6_addr_t *ap, *pap;
2461 2446  
2462 2447                                  left = rthdr->ip6r0_segleft;
2463 2448                                  prthdr = (ip6_rthdr0_t *)pi_opt;
2464 2449                                  pap = (in6_addr_t *)(prthdr + 1);
2465 2450                                  ap = (in6_addr_t *)(rthdr + 1);
2466 2451                                  /*
2467 2452                                   * First eight bytes except seg_left
2468 2453                                   * does not change en route.
2469 2454                                   */
2470 2455                                  bcopy(oi_opt, pi_opt, 8);
2471 2456                                  prthdr->ip6r0_segleft = 0;
2472 2457                                  /*
2473 2458                                   * First address has been moved to
2474 2459                                   * the destination address of the
2475 2460                                   * ip header by ip_massage_options_v6.
2476 2461                                   * And the real destination address is
2477 2462                                   * in the last address part of the
2478 2463                                   * option.
2479 2464                                   */
2480 2465                                  *pap = oip6h->ip6_dst;
2481 2466                                  for (i = 1; i < left - 1; i++)
2482 2467                                          pap[i] = ap[i - 1];
2483 2468                                  ip6h->ip6_dst = *(ap + left - 1);
2484 2469                          } else {
2485 2470                                  bcopy(oi_opt, pi_opt, ehdrlen);
2486 2471                          }
2487 2472                          rthdr = (ip6_rthdr0_t *)pi_opt;
2488 2473                          prev_nexthdr = (uint8_t *)&rthdr->ip6r0_nxt;
2489 2474                          break;
2490 2475                  case IPPROTO_DSTOPTS:
2491 2476                          /*
2492 2477                           * Destination options are tricky.  If there is
2493 2478                           * a terminal (e.g. non-IPv6-extension) header
2494 2479                           * following the destination options, don't
2495 2480                           * reset prev_nexthdr or advance the AH insertion
2496 2481                           * point and just treat this as a terminal header.
2497 2482                           *
2498 2483                           * If this is an inbound packet, just deal with
2499 2484                           * it as is.
2500 2485                           */
2501 2486                          dsthdr = (ip6_dest_t *)oi_opt;
2502 2487                          /*
2503 2488                           * XXX I hope common-subexpression elimination
2504 2489                           * saves us the double-evaluate.
2505 2490                           */
2506 2491                          if (outbound && dsthdr->ip6d_nxt != IPPROTO_ROUTING &&
2507 2492                              dsthdr->ip6d_nxt != IPPROTO_HOPOPTS)
2508 2493                                  goto terminal_hdr;
2509 2494                          nexthdr = dsthdr->ip6d_nxt;
2510 2495                          ehdrlen = 8 * (dsthdr->ip6d_len + 1);
2511 2496                          ret = ah_fix_tlv_options_v6(oi_opt, pi_opt, ehdrlen,
2512 2497                              IPPROTO_DSTOPTS, copy_always);
2513 2498                          /*
2514 2499                           * Return a zero offset indicating error if there
2515 2500                           * was error.
2516 2501                           */
2517 2502                          if (ret == -1)
2518 2503                                  return (0);
2519 2504                          break;
2520 2505                  case IPPROTO_AH:
2521 2506                          /*
2522 2507                           * Be conservative in what you send.  We shouldn't
2523 2508                           * see two same-scoped AH's in one packet.
2524 2509                           * (Inner-IP-scoped AH will be hit by terminal
2525 2510                           * header of IP or IPv6.)
2526 2511                           */
2527 2512                          ASSERT(!outbound);
2528 2513                          return ((uint_t)(pi_opt - (uint8_t *)ip6h));
2529 2514                  default:
2530 2515                          ASSERT(outbound);
2531 2516  terminal_hdr:
2532 2517                          *prev_nexthdr = IPPROTO_AH;
2533 2518                          ah = (ah_t *)pi_opt;
2534 2519                          ah->ah_nexthdr = nexthdr;
2535 2520                          return ((uint_t)(pi_opt - (uint8_t *)ip6h));
2536 2521                  }
2537 2522                  pi_opt += ehdrlen;
2538 2523                  oi_opt += ehdrlen;
2539 2524          }
2540 2525          /* NOTREACHED */
2541 2526  }
2542 2527  
2543 2528  static boolean_t
2544 2529  ah_finish_up(ah_t *phdr_ah, ah_t *inbound_ah, ipsa_t *assoc,
2545 2530      int ah_data_sz, int ah_align_sz, ipsecah_stack_t *ahstack)
2546 2531  {
2547 2532          int i;
2548 2533  
2549 2534          /*
2550 2535           * Padding :
2551 2536           *
2552 2537           * 1) Authentication data may have to be padded
2553 2538           * before ICV calculation if ICV is not a multiple
2554 2539           * of 64 bits. This padding is arbitrary and transmitted
2555 2540           * with the packet at the end of the authentication data.
2556 2541           * Payload length should include the padding bytes.
2557 2542           *
2558 2543           * 2) Explicit padding of the whole datagram may be
2559 2544           * required by the algorithm which need not be
2560 2545           * transmitted. It is assumed that this will be taken
2561 2546           * care by the algorithm module.
2562 2547           */
2563 2548          bzero(phdr_ah + 1, ah_data_sz); /* Zero out ICV for pseudo-hdr. */
2564 2549  
2565 2550          if (inbound_ah == NULL) {
2566 2551                  /* Outbound AH datagram. */
2567 2552  
2568 2553                  phdr_ah->ah_length = (ah_align_sz >> 2) + 1;
2569 2554                  phdr_ah->ah_reserved = 0;
2570 2555                  phdr_ah->ah_spi = assoc->ipsa_spi;
2571 2556  
2572 2557                  phdr_ah->ah_replay =
2573 2558                      htonl(atomic_inc_32_nv(&assoc->ipsa_replay));
2574 2559                  if (phdr_ah->ah_replay == 0 && assoc->ipsa_replay_wsize != 0) {
2575 2560                          /*
2576 2561                           * XXX We have replay counter wrapping.  We probably
2577 2562                           * want to nuke this SA (and its peer).
2578 2563                           */
2579 2564                          ipsec_assocfailure(info.mi_idnum, 0, 0,
2580 2565                              SL_ERROR | SL_CONSOLE | SL_WARN,
2581 2566                              "Outbound AH SA (0x%x), dst %s has wrapped "
2582 2567                              "sequence.\n", phdr_ah->ah_spi,
2583 2568                              assoc->ipsa_dstaddr, assoc->ipsa_addrfam,
2584 2569                              ahstack->ipsecah_netstack);
2585 2570  
2586 2571                          sadb_replay_delete(assoc);
2587 2572                          /* Caller will free phdr_mp and return NULL. */
2588 2573                          return (B_FALSE);
2589 2574                  }
2590 2575  
2591 2576                  if (ah_data_sz != ah_align_sz) {
2592 2577                          uchar_t *pad = ((uchar_t *)phdr_ah + sizeof (ah_t) +
2593 2578                              ah_data_sz);
2594 2579  
2595 2580                          for (i = 0; i < (ah_align_sz - ah_data_sz); i++) {
2596 2581                                  pad[i] = (uchar_t)i;    /* Fill the padding */
2597 2582                          }
2598 2583                  }
2599 2584          } else {
2600 2585                  /* Inbound AH datagram. */
2601 2586                  phdr_ah->ah_nexthdr = inbound_ah->ah_nexthdr;
2602 2587                  phdr_ah->ah_length = inbound_ah->ah_length;
2603 2588                  phdr_ah->ah_reserved = 0;
2604 2589                  ASSERT(inbound_ah->ah_spi == assoc->ipsa_spi);
2605 2590                  phdr_ah->ah_spi = inbound_ah->ah_spi;
2606 2591                  phdr_ah->ah_replay = inbound_ah->ah_replay;
2607 2592  
2608 2593                  if (ah_data_sz != ah_align_sz) {
2609 2594                          uchar_t *opad = ((uchar_t *)inbound_ah +
2610 2595                              sizeof (ah_t) + ah_data_sz);
2611 2596                          uchar_t *pad = ((uchar_t *)phdr_ah + sizeof (ah_t) +
2612 2597                              ah_data_sz);
2613 2598  
2614 2599                          for (i = 0; i < (ah_align_sz - ah_data_sz); i++) {
2615 2600                                  pad[i] = opad[i];       /* Copy the padding */
2616 2601                          }
2617 2602                  }
2618 2603          }
2619 2604  
2620 2605          return (B_TRUE);
2621 2606  }
2622 2607  
2623 2608  /*
2624 2609   * Called upon failing the inbound ICV check. The message passed as
2625 2610   * argument is freed.
2626 2611   */
2627 2612  static void
2628 2613  ah_log_bad_auth(mblk_t *mp, ip_recv_attr_t *ira, ipsec_crypto_t *ic)
2629 2614  {
2630 2615          boolean_t       isv4 = (ira->ira_flags & IRAF_IS_IPV4);
2631 2616          ipsa_t          *assoc = ira->ira_ipsec_ah_sa;
2632 2617          int             af;
2633 2618          void            *addr;
2634 2619          netstack_t      *ns = ira->ira_ill->ill_ipst->ips_netstack;
2635 2620          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
2636 2621          ipsec_stack_t   *ipss = ns->netstack_ipsec;
2637 2622  
2638 2623          ASSERT(mp->b_datap->db_type == M_DATA);
2639 2624  
2640 2625          mp->b_rptr -= ic->ic_skip_len;
2641 2626  
2642 2627          if (isv4) {
2643 2628                  ipha_t *ipha = (ipha_t *)mp->b_rptr;
2644 2629                  addr = &ipha->ipha_dst;
2645 2630                  af = AF_INET;
2646 2631          } else {
2647 2632                  ip6_t *ip6h = (ip6_t *)mp->b_rptr;
2648 2633                  addr = &ip6h->ip6_dst;
2649 2634                  af = AF_INET6;
2650 2635          }
2651 2636  
2652 2637          /*
2653 2638           * Log the event. Don't print to the console, block
2654 2639           * potential denial-of-service attack.
2655 2640           */
2656 2641          AH_BUMP_STAT(ahstack, bad_auth);
2657 2642  
2658 2643          ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
2659 2644              "AH Authentication failed spi %x, dst_addr %s",
2660 2645              assoc->ipsa_spi, addr, af, ahstack->ipsecah_netstack);
2661 2646  
2662 2647          IP_AH_BUMP_STAT(ipss, in_discards);
2663 2648          ip_drop_packet(mp, B_TRUE, ira->ira_ill,
2664 2649              DROPPER(ipss, ipds_ah_bad_auth),
2665 2650              &ahstack->ah_dropper);
2666 2651  }
2667 2652  
2668 2653  /*
2669 2654   * Kernel crypto framework callback invoked after completion of async
2670 2655   * crypto requests for outbound packets.
2671 2656   */
2672 2657  static void
2673 2658  ah_kcf_callback_outbound(void *arg, int status)
2674 2659  {
2675 2660          mblk_t          *mp = (mblk_t *)arg;
2676 2661          mblk_t          *async_mp;
2677 2662          netstack_t      *ns;
2678 2663          ipsec_stack_t   *ipss;
2679 2664          ipsecah_stack_t *ahstack;
2680 2665          mblk_t          *data_mp;
2681 2666          ip_xmit_attr_t  ixas;
2682 2667          ipsec_crypto_t  *ic;
2683 2668          ill_t           *ill;
2684 2669  
2685 2670          /*
2686 2671           * First remove the ipsec_crypto_t mblk
2687 2672           * Note that we need to ipsec_free_crypto_data(mp) once done with ic.
2688 2673           */
2689 2674          async_mp = ipsec_remove_crypto_data(mp, &ic);
2690 2675          ASSERT(async_mp != NULL);
2691 2676  
2692 2677          /*
2693 2678           * Extract the ip_xmit_attr_t from the first mblk.
2694 2679           * Verifies that the netstack and ill is still around; could
2695 2680           * have vanished while kEf was doing its work.
2696 2681           * On succesful return we have a nce_t and the ill/ipst can't
2697 2682           * disappear until we do the nce_refrele in ixa_cleanup.
2698 2683           */
2699 2684          data_mp = async_mp->b_cont;
2700 2685          async_mp->b_cont = NULL;
2701 2686          if (!ip_xmit_attr_from_mblk(async_mp, &ixas)) {
2702 2687                  /* Disappeared on us - no ill/ipst for MIB */
2703 2688                  if (ixas.ixa_nce != NULL) {
2704 2689                          ill = ixas.ixa_nce->nce_ill;
2705 2690                          BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2706 2691                          ip_drop_output("ipIfStatsOutDiscards", data_mp, ill);
2707 2692                  }
2708 2693                  freemsg(data_mp);
2709 2694                  goto done;
2710 2695          }
2711 2696          ns = ixas.ixa_ipst->ips_netstack;
2712 2697          ahstack = ns->netstack_ipsecah;
2713 2698          ipss = ns->netstack_ipsec;
2714 2699          ill = ixas.ixa_nce->nce_ill;
2715 2700  
2716 2701          if (status == CRYPTO_SUCCESS) {
2717 2702                  data_mp = ah_auth_out_done(data_mp, &ixas, ic);
2718 2703                  if (data_mp == NULL)
2719 2704                          goto done;
2720 2705  
2721 2706                  (void) ip_output_post_ipsec(data_mp, &ixas);
2722 2707          } else {
2723 2708                  /* Outbound shouldn't see invalid MAC */
2724 2709                  ASSERT(status != CRYPTO_INVALID_MAC);
2725 2710  
2726 2711                  ah1dbg(ahstack,
2727 2712                      ("ah_kcf_callback_outbound: crypto failed with 0x%x\n",
2728 2713                      status));
2729 2714                  AH_BUMP_STAT(ahstack, crypto_failures);
2730 2715                  AH_BUMP_STAT(ahstack, out_discards);
2731 2716  
2732 2717                  ip_drop_packet(data_mp, B_FALSE, ill,
2733 2718                      DROPPER(ipss, ipds_ah_crypto_failed),
2734 2719                      &ahstack->ah_dropper);
2735 2720                  BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2736 2721          }
2737 2722  done:
2738 2723          ixa_cleanup(&ixas);
2739 2724          (void) ipsec_free_crypto_data(mp);
2740 2725  }
2741 2726  
2742 2727  /*
2743 2728   * Kernel crypto framework callback invoked after completion of async
2744 2729   * crypto requests for inbound packets.
2745 2730   */
2746 2731  static void
2747 2732  ah_kcf_callback_inbound(void *arg, int status)
2748 2733  {
2749 2734          mblk_t          *mp = (mblk_t *)arg;
2750 2735          mblk_t          *async_mp;
2751 2736          netstack_t      *ns;
2752 2737          ipsec_stack_t   *ipss;
2753 2738          ipsecah_stack_t *ahstack;
2754 2739          mblk_t          *data_mp;
2755 2740          ip_recv_attr_t  iras;
2756 2741          ipsec_crypto_t  *ic;
2757 2742  
2758 2743          /*
2759 2744           * First remove the ipsec_crypto_t mblk
2760 2745           * Note that we need to ipsec_free_crypto_data(mp) once done with ic.
2761 2746           */
2762 2747          async_mp = ipsec_remove_crypto_data(mp, &ic);
2763 2748          ASSERT(async_mp != NULL);
2764 2749  
2765 2750          /*
2766 2751           * Extract the ip_xmit_attr_t from the first mblk.
2767 2752           * Verifies that the netstack and ill is still around; could
2768 2753           * have vanished while kEf was doing its work.
2769 2754           */
2770 2755          data_mp = async_mp->b_cont;
2771 2756          async_mp->b_cont = NULL;
2772 2757          if (!ip_recv_attr_from_mblk(async_mp, &iras)) {
2773 2758                  /* The ill or ip_stack_t disappeared on us */
2774 2759                  ip_drop_input("ip_recv_attr_from_mblk", data_mp, NULL);
2775 2760                  freemsg(data_mp);
2776 2761                  goto done;
2777 2762          }
2778 2763          ns = iras.ira_ill->ill_ipst->ips_netstack;
2779 2764          ahstack = ns->netstack_ipsecah;
2780 2765          ipss = ns->netstack_ipsec;
2781 2766  
2782 2767          if (status == CRYPTO_SUCCESS) {
2783 2768                  data_mp = ah_auth_in_done(data_mp, &iras, ic);
2784 2769                  if (data_mp == NULL)
2785 2770                          goto done;
2786 2771  
2787 2772                  /* finish IPsec processing */
2788 2773                  ip_input_post_ipsec(data_mp, &iras);
2789 2774  
2790 2775          } else if (status == CRYPTO_INVALID_MAC) {
2791 2776                  ah_log_bad_auth(data_mp, &iras, ic);
2792 2777          } else {
2793 2778                  ah1dbg(ahstack,
2794 2779                      ("ah_kcf_callback_inbound: crypto failed with 0x%x\n",
2795 2780                      status));
2796 2781                  AH_BUMP_STAT(ahstack, crypto_failures);
2797 2782                  IP_AH_BUMP_STAT(ipss, in_discards);
2798 2783                  ip_drop_packet(data_mp, B_TRUE, iras.ira_ill,
2799 2784                      DROPPER(ipss, ipds_ah_crypto_failed),
2800 2785                      &ahstack->ah_dropper);
2801 2786                  BUMP_MIB(iras.ira_ill->ill_ip_mib, ipIfStatsInDiscards);
2802 2787          }
2803 2788  done:
2804 2789          ira_cleanup(&iras, B_TRUE);
2805 2790          (void) ipsec_free_crypto_data(mp);
2806 2791  }
2807 2792  
2808 2793  /*
2809 2794   * Invoked on kernel crypto failure during inbound and outbound processing.
2810 2795   */
2811 2796  static void
2812 2797  ah_crypto_failed(mblk_t *data_mp, boolean_t is_inbound, int kef_rc,
2813 2798      ill_t *ill, ipsecah_stack_t *ahstack)
2814 2799  {
2815 2800          ipsec_stack_t   *ipss = ahstack->ipsecah_netstack->netstack_ipsec;
2816 2801  
2817 2802          ah1dbg(ahstack, ("crypto failed for %s AH with 0x%x\n",
2818 2803              is_inbound ? "inbound" : "outbound", kef_rc));
2819 2804          ip_drop_packet(data_mp, is_inbound, ill,
2820 2805              DROPPER(ipss, ipds_ah_crypto_failed),
2821 2806              &ahstack->ah_dropper);
2822 2807          AH_BUMP_STAT(ahstack, crypto_failures);
2823 2808          if (is_inbound)
2824 2809                  IP_AH_BUMP_STAT(ipss, in_discards);
2825 2810          else
2826 2811                  AH_BUMP_STAT(ahstack, out_discards);
2827 2812  }
2828 2813  
2829 2814  /*
2830 2815   * Helper macros for the ah_submit_req_{inbound,outbound}() functions.
2831 2816   */
2832 2817  
2833 2818  /*
2834 2819   * A statement-equivalent macro, _cr MUST point to a modifiable
2835 2820   * crypto_call_req_t.
2836 2821   */
2837 2822  #define AH_INIT_CALLREQ(_cr, _mp, _callback)            \
2838 2823          (_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_ALWAYS_QUEUE; \
2839 2824          (_cr)->cr_callback_arg = (_mp);                         \
2840 2825          (_cr)->cr_callback_func = (_callback)
2841 2826  
2842 2827  #define AH_INIT_CRYPTO_DATA(data, msglen, mblk) {                       \
2843 2828          (data)->cd_format = CRYPTO_DATA_MBLK;                           \
2844 2829          (data)->cd_mp = mblk;                                           \
2845 2830          (data)->cd_offset = 0;                                          \
2846 2831          (data)->cd_length = msglen;                                     \
2847 2832  }
2848 2833  
2849 2834  #define AH_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) {                       \
2850 2835          (mac)->cd_format = CRYPTO_DATA_RAW;                             \
2851 2836          (mac)->cd_offset = 0;                                           \
2852 2837          (mac)->cd_length = icvlen;                                      \
2853 2838          (mac)->cd_raw.iov_base = icvbuf;                                \
2854 2839          (mac)->cd_raw.iov_len = icvlen;                                 \
2855 2840  }
2856 2841  
2857 2842  /*
2858 2843   * Submit an inbound packet for processing by the crypto framework.
2859 2844   */
2860 2845  static mblk_t *
2861 2846  ah_submit_req_inbound(mblk_t *phdr_mp, ip_recv_attr_t *ira,
2862 2847      size_t skip_len, uint32_t ah_offset, ipsa_t *assoc)
2863 2848  {
2864 2849          int kef_rc;
2865 2850          mblk_t *mp;
2866 2851          crypto_call_req_t call_req, *callrp;
2867 2852          uint_t icv_len = assoc->ipsa_mac_len;
2868 2853          crypto_ctx_template_t ctx_tmpl;
2869 2854          ipsecah_stack_t *ahstack;
2870 2855          ipsec_crypto_t  *ic, icstack;
2871 2856          boolean_t force = (assoc->ipsa_flags & IPSA_F_ASYNC);
2872 2857  
2873 2858          ahstack = ira->ira_ill->ill_ipst->ips_netstack->netstack_ipsecah;
2874 2859  
2875 2860          ASSERT(phdr_mp != NULL);
2876 2861          ASSERT(phdr_mp->b_datap->db_type == M_DATA);
2877 2862  
2878 2863          if (force) {
2879 2864                  /* We are doing asynch; allocate mblks to hold state */
2880 2865                  if ((mp = ip_recv_attr_to_mblk(ira)) == NULL ||
2881 2866                      (mp = ipsec_add_crypto_data(mp, &ic)) == NULL) {
2882 2867                          BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
2883 2868                          ip_drop_input("ipIfStatsInDiscards", phdr_mp,
2884 2869                              ira->ira_ill);
2885 2870                          freemsg(phdr_mp);
2886 2871                          return (NULL);
2887 2872                  }
2888 2873  
2889 2874                  linkb(mp, phdr_mp);
2890 2875                  callrp = &call_req;
2891 2876                  AH_INIT_CALLREQ(callrp, mp, ah_kcf_callback_inbound);
2892 2877          } else {
2893 2878                  /*
2894 2879                   * If we know we are going to do sync then ipsec_crypto_t
2895 2880                   * should be on the stack.
2896 2881                   */
2897 2882                  ic = &icstack;
2898 2883                  bzero(ic, sizeof (*ic));
2899 2884                  callrp = NULL;
2900 2885          }
2901 2886  
2902 2887          /* init arguments for the crypto framework */
2903 2888          AH_INIT_CRYPTO_DATA(&ic->ic_crypto_data, AH_MSGSIZE(phdr_mp),
2904 2889              phdr_mp);
2905 2890  
2906 2891          AH_INIT_CRYPTO_MAC(&ic->ic_crypto_mac, icv_len,
2907 2892              (char *)phdr_mp->b_cont->b_rptr - skip_len + ah_offset +
2908 2893              sizeof (ah_t));
2909 2894  
2910 2895          ic->ic_skip_len = skip_len;
2911 2896  
2912 2897          IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, ctx_tmpl);
2913 2898  
2914 2899          /* call KEF to do the MAC operation */
2915 2900          kef_rc = crypto_mac_verify(&assoc->ipsa_amech,
2916 2901              &ic->ic_crypto_data, &assoc->ipsa_kcfauthkey, ctx_tmpl,
2917 2902              &ic->ic_crypto_mac, callrp);
2918 2903  
2919 2904          switch (kef_rc) {
2920 2905          case CRYPTO_SUCCESS:
2921 2906                  AH_BUMP_STAT(ahstack, crypto_sync);
2922 2907                  phdr_mp = ah_auth_in_done(phdr_mp, ira, ic);
2923 2908                  if (force) {
2924 2909                          /* Free mp after we are done with ic */
2925 2910                          mp = ipsec_free_crypto_data(mp);
2926 2911                          (void) ip_recv_attr_free_mblk(mp);
2927 2912                  }
2928 2913                  return (phdr_mp);
2929 2914          case CRYPTO_QUEUED:
2930 2915                  /* ah_kcf_callback_inbound() will be invoked on completion */
2931 2916                  AH_BUMP_STAT(ahstack, crypto_async);
2932 2917                  return (NULL);
2933 2918          case CRYPTO_INVALID_MAC:
2934 2919                  /* Free mp after we are done with ic */
2935 2920                  AH_BUMP_STAT(ahstack, crypto_sync);
2936 2921                  BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
2937 2922                  ah_log_bad_auth(phdr_mp, ira, ic);
2938 2923                  /* phdr_mp was passed to ip_drop_packet */
2939 2924                  if (force) {
2940 2925                          mp = ipsec_free_crypto_data(mp);
2941 2926                          (void) ip_recv_attr_free_mblk(mp);
2942 2927                  }
2943 2928                  return (NULL);
2944 2929          }
2945 2930  
2946 2931          if (force) {
2947 2932                  mp = ipsec_free_crypto_data(mp);
2948 2933                  phdr_mp = ip_recv_attr_free_mblk(mp);
2949 2934          }
2950 2935          BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
2951 2936          ah_crypto_failed(phdr_mp, B_TRUE, kef_rc, ira->ira_ill, ahstack);
2952 2937          /* phdr_mp was passed to ip_drop_packet */
2953 2938          return (NULL);
2954 2939  }
2955 2940  
2956 2941  /*
2957 2942   * Submit an outbound packet for processing by the crypto framework.
2958 2943   */
2959 2944  static mblk_t *
2960 2945  ah_submit_req_outbound(mblk_t *phdr_mp, ip_xmit_attr_t *ixa,
2961 2946      size_t skip_len, ipsa_t *assoc)
2962 2947  {
2963 2948          int kef_rc;
2964 2949          mblk_t *mp;
2965 2950          crypto_call_req_t call_req, *callrp;
2966 2951          uint_t icv_len = assoc->ipsa_mac_len;
2967 2952          ipsecah_stack_t *ahstack;
2968 2953          ipsec_crypto_t  *ic, icstack;
2969 2954          ill_t           *ill = ixa->ixa_nce->nce_ill;
2970 2955          boolean_t force = (assoc->ipsa_flags & IPSA_F_ASYNC);
2971 2956  
2972 2957          ahstack = ill->ill_ipst->ips_netstack->netstack_ipsecah;
2973 2958  
2974 2959          ASSERT(phdr_mp != NULL);
2975 2960          ASSERT(phdr_mp->b_datap->db_type == M_DATA);
2976 2961  
2977 2962          if (force) {
2978 2963                  /* We are doing asynch; allocate mblks to hold state */
2979 2964                  if ((mp = ip_xmit_attr_to_mblk(ixa)) == NULL ||
2980 2965                      (mp = ipsec_add_crypto_data(mp, &ic)) == NULL) {
2981 2966                          BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
2982 2967                          ip_drop_output("ipIfStatsOutDiscards", phdr_mp, ill);
2983 2968                          freemsg(phdr_mp);
2984 2969                          return (NULL);
2985 2970                  }
2986 2971                  linkb(mp, phdr_mp);
2987 2972                  callrp = &call_req;
2988 2973                  AH_INIT_CALLREQ(callrp, mp, ah_kcf_callback_outbound);
2989 2974          } else {
2990 2975                  /*
2991 2976                   * If we know we are going to do sync then ipsec_crypto_t
2992 2977                   * should be on the stack.
2993 2978                   */
2994 2979                  ic = &icstack;
2995 2980                  bzero(ic, sizeof (*ic));
2996 2981                  callrp = NULL;
2997 2982          }
2998 2983  
2999 2984          /* init arguments for the crypto framework */
3000 2985          AH_INIT_CRYPTO_DATA(&ic->ic_crypto_data, AH_MSGSIZE(phdr_mp),
3001 2986              phdr_mp);
3002 2987  
3003 2988          AH_INIT_CRYPTO_MAC(&ic->ic_crypto_mac, icv_len,
3004 2989              (char *)phdr_mp->b_wptr);
3005 2990  
3006 2991          ic->ic_skip_len = skip_len;
3007 2992  
3008 2993          ASSERT(ixa->ixa_ipsec_ah_sa != NULL);
3009 2994  
3010 2995          /* call KEF to do the MAC operation */
3011 2996          kef_rc = crypto_mac(&assoc->ipsa_amech, &ic->ic_crypto_data,
3012 2997              &assoc->ipsa_kcfauthkey, assoc->ipsa_authtmpl,
3013 2998              &ic->ic_crypto_mac, callrp);
3014 2999  
3015 3000          switch (kef_rc) {
3016 3001          case CRYPTO_SUCCESS:
3017 3002                  AH_BUMP_STAT(ahstack, crypto_sync);
3018 3003                  phdr_mp = ah_auth_out_done(phdr_mp, ixa, ic);
3019 3004                  if (force) {
3020 3005                          /* Free mp after we are done with ic */
3021 3006                          mp = ipsec_free_crypto_data(mp);
3022 3007                          (void) ip_xmit_attr_free_mblk(mp);
3023 3008                  }
3024 3009                  return (phdr_mp);
3025 3010          case CRYPTO_QUEUED:
3026 3011                  /* ah_kcf_callback_outbound() will be invoked on completion */
3027 3012                  AH_BUMP_STAT(ahstack, crypto_async);
3028 3013                  return (NULL);
3029 3014          }
3030 3015  
3031 3016          if (force) {
3032 3017                  mp = ipsec_free_crypto_data(mp);
3033 3018                  phdr_mp = ip_xmit_attr_free_mblk(mp);
3034 3019          }
3035 3020          BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
3036 3021          ah_crypto_failed(phdr_mp, B_FALSE, kef_rc, NULL, ahstack);
3037 3022          /* phdr_mp was passed to ip_drop_packet */
3038 3023          return (NULL);
3039 3024  }
3040 3025  
3041 3026  /*
3042 3027   * This function constructs a pseudo header by looking at the IP header
3043 3028   * and options if any. This is called for both outbound and inbound,
3044 3029   * before computing the ICV.
3045 3030   */
3046 3031  static mblk_t *
3047 3032  ah_process_ip_options_v6(mblk_t *mp, ipsa_t *assoc, int *length_to_skip,
3048 3033      uint_t ah_data_sz, boolean_t outbound, ipsecah_stack_t *ahstack)
3049 3034  {
3050 3035          ip6_t   *ip6h;
3051 3036          ip6_t   *oip6h;
3052 3037          mblk_t  *phdr_mp;
3053 3038          int option_length;
3054 3039          uint_t  ah_align_sz;
3055 3040          uint_t ah_offset;
3056 3041          int hdr_size;
3057 3042  
3058 3043          /*
3059 3044           * Allocate space for the authentication data also. It is
3060 3045           * useful both during the ICV calculation where we need to
3061 3046           * feed in zeroes and while sending the datagram back to IP
3062 3047           * where we will be using the same space.
3063 3048           *
3064 3049           * We need to allocate space for padding bytes if it is not
3065 3050           * a multiple of IPV6_PADDING_ALIGN.
3066 3051           *
3067 3052           * In addition, we allocate space for the ICV computed by
3068 3053           * the kernel crypto framework, saving us a separate kmem
3069 3054           * allocation down the road.
3070 3055           */
3071 3056  
3072 3057          ah_align_sz = P2ALIGN(ah_data_sz + IPV6_PADDING_ALIGN - 1,
3073 3058              IPV6_PADDING_ALIGN);
3074 3059  
3075 3060          ASSERT(ah_align_sz >= ah_data_sz);
3076 3061  
3077 3062          hdr_size = ipsec_ah_get_hdr_size_v6(mp, B_FALSE);
3078 3063          option_length = hdr_size - IPV6_HDR_LEN;
3079 3064  
3080 3065          /* This was not included in ipsec_ah_get_hdr_size_v6() */
3081 3066          hdr_size += (sizeof (ah_t) + ah_align_sz);
3082 3067  
3083 3068          if (!outbound && (MBLKL(mp) < hdr_size)) {
3084 3069                  /*
3085 3070                   * We have post-AH header options in a separate mblk,
3086 3071                   * a pullup is required.
3087 3072                   */
3088 3073                  if (!pullupmsg(mp, hdr_size))
3089 3074                          return (NULL);
3090 3075          }
3091 3076  
3092 3077          if ((phdr_mp = allocb_tmpl(hdr_size + ah_data_sz, mp)) == NULL) {
3093 3078                  return (NULL);
3094 3079          }
3095 3080  
3096 3081          oip6h = (ip6_t *)mp->b_rptr;
3097 3082  
3098 3083          /*
3099 3084           * Form the basic IP header first. Zero out the header
3100 3085           * so that the mutable fields are zeroed out.
3101 3086           */
3102 3087          ip6h = (ip6_t *)phdr_mp->b_rptr;
3103 3088          bzero(ip6h, sizeof (ip6_t));
3104 3089          ip6h->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW;
3105 3090  
3106 3091          if (outbound) {
3107 3092                  /*
3108 3093                   * Include the size of AH and authentication data.
3109 3094                   * This is how our recipient would compute the
3110 3095                   * authentication data. Look at what we do in the
3111 3096                   * inbound case below.
3112 3097                   */
3113 3098                  ip6h->ip6_plen = htons(ntohs(oip6h->ip6_plen) +
3114 3099                      sizeof (ah_t) + ah_align_sz);
3115 3100          } else {
3116 3101                  ip6h->ip6_plen = oip6h->ip6_plen;
3117 3102          }
3118 3103  
3119 3104          ip6h->ip6_src = oip6h->ip6_src;
3120 3105          ip6h->ip6_dst = oip6h->ip6_dst;
3121 3106  
3122 3107          *length_to_skip = IPV6_HDR_LEN;
3123 3108          if (option_length == 0) {
3124 3109                  /* Form the AH header */
3125 3110                  ip6h->ip6_nxt = IPPROTO_AH;
3126 3111                  ((ah_t *)(ip6h + 1))->ah_nexthdr = oip6h->ip6_nxt;
3127 3112                  ah_offset = *length_to_skip;
3128 3113          } else {
3129 3114                  ip6h->ip6_nxt = oip6h->ip6_nxt;
3130 3115                  /* option_length does not include the AH header's size */
3131 3116                  *length_to_skip += option_length;
3132 3117  
3133 3118                  ah_offset = ah_fix_phdr_v6(ip6h, oip6h, outbound, B_FALSE);
3134 3119                  if (ah_offset == 0) {
3135 3120                          return (NULL);
3136 3121                  }
3137 3122          }
3138 3123  
3139 3124          if (!ah_finish_up(((ah_t *)((uint8_t *)ip6h + ah_offset)),
3140 3125              (outbound ? NULL : ((ah_t *)((uint8_t *)oip6h + ah_offset))),
3141 3126              assoc, ah_data_sz, ah_align_sz, ahstack)) {
3142 3127                  freeb(phdr_mp);
3143 3128                  /*
3144 3129                   * Returning NULL will tell the caller to
3145 3130                   * IPSA_REFELE(), free the memory, etc.
3146 3131                   */
3147 3132                  return (NULL);
3148 3133          }
3149 3134  
3150 3135          phdr_mp->b_wptr = ((uint8_t *)ip6h + ah_offset + sizeof (ah_t) +
3151 3136              ah_align_sz);
3152 3137          if (!outbound)
3153 3138                  *length_to_skip += sizeof (ah_t) + ah_align_sz;
3154 3139          return (phdr_mp);
3155 3140  }
3156 3141  
3157 3142  /*
3158 3143   * This function constructs a pseudo header by looking at the IP header
3159 3144   * and options if any. This is called for both outbound and inbound,
3160 3145   * before computing the ICV.
3161 3146   */
3162 3147  static mblk_t *
3163 3148  ah_process_ip_options_v4(mblk_t *mp, ipsa_t *assoc, int *length_to_skip,
3164 3149      uint_t ah_data_sz, boolean_t outbound, ipsecah_stack_t *ahstack)
3165 3150  {
3166 3151          ipoptp_t opts;
3167 3152          uint32_t option_length;
3168 3153          ipha_t  *ipha;
3169 3154          ipha_t  *oipha;
3170 3155          mblk_t  *phdr_mp;
3171 3156          int      size;
3172 3157          uchar_t *optptr;
3173 3158          uint8_t optval;
3174 3159          uint8_t optlen;
3175 3160          ipaddr_t dst;
3176 3161          uint32_t v_hlen_tos_len;
3177 3162          int ip_hdr_length;
3178 3163          uint_t  ah_align_sz;
3179 3164          uint32_t off;
3180 3165  
3181 3166  #ifdef  _BIG_ENDIAN
3182 3167  #define V_HLEN  (v_hlen_tos_len >> 24)
3183 3168  #else
3184 3169  #define V_HLEN  (v_hlen_tos_len & 0xFF)
3185 3170  #endif
3186 3171  
3187 3172          oipha = (ipha_t *)mp->b_rptr;
3188 3173          v_hlen_tos_len = ((uint32_t *)oipha)[0];
3189 3174  
3190 3175          /*
3191 3176           * Allocate space for the authentication data also. It is
3192 3177           * useful both during the ICV calculation where we need to
3193 3178           * feed in zeroes and while sending the datagram back to IP
3194 3179           * where we will be using the same space.
3195 3180           *
3196 3181           * We need to allocate space for padding bytes if it is not
3197 3182           * a multiple of IPV4_PADDING_ALIGN.
3198 3183           *
3199 3184           * In addition, we allocate space for the ICV computed by
3200 3185           * the kernel crypto framework, saving us a separate kmem
3201 3186           * allocation down the road.
3202 3187           */
3203 3188  
3204 3189          ah_align_sz = P2ALIGN(ah_data_sz + IPV4_PADDING_ALIGN - 1,
3205 3190              IPV4_PADDING_ALIGN);
3206 3191  
3207 3192          ASSERT(ah_align_sz >= ah_data_sz);
3208 3193  
3209 3194          size = IP_SIMPLE_HDR_LENGTH + sizeof (ah_t) + ah_align_sz +
3210 3195              ah_data_sz;
3211 3196  
3212 3197          if (V_HLEN != IP_SIMPLE_HDR_VERSION) {
3213 3198                  option_length = oipha->ipha_version_and_hdr_length -
3214 3199                      (uint8_t)((IP_VERSION << 4) +
3215 3200                      IP_SIMPLE_HDR_LENGTH_IN_WORDS);
3216 3201                  option_length <<= 2;
3217 3202                  size += option_length;
3218 3203          }
3219 3204  
3220 3205          if ((phdr_mp = allocb_tmpl(size, mp)) == NULL) {
3221 3206                  return (NULL);
3222 3207          }
3223 3208  
3224 3209          /*
3225 3210           * Form the basic IP header first.
3226 3211           */
3227 3212          ipha = (ipha_t *)phdr_mp->b_rptr;
3228 3213          ipha->ipha_version_and_hdr_length = oipha->ipha_version_and_hdr_length;
3229 3214          ipha->ipha_type_of_service = 0;
3230 3215  
3231 3216          if (outbound) {
3232 3217                  /*
3233 3218                   * Include the size of AH and authentication data.
3234 3219                   * This is how our recipient would compute the
3235 3220                   * authentication data. Look at what we do in the
3236 3221                   * inbound case below.
3237 3222                   */
3238 3223                  ipha->ipha_length = ntohs(htons(oipha->ipha_length) +
3239 3224                      sizeof (ah_t) + ah_align_sz);
3240 3225          } else {
3241 3226                  ipha->ipha_length = oipha->ipha_length;
3242 3227          }
3243 3228  
3244 3229          ipha->ipha_ident = oipha->ipha_ident;
3245 3230          ipha->ipha_fragment_offset_and_flags = 0;
3246 3231          ipha->ipha_ttl = 0;
3247 3232          ipha->ipha_protocol = IPPROTO_AH;
3248 3233          ipha->ipha_hdr_checksum = 0;
3249 3234          ipha->ipha_src = oipha->ipha_src;
3250 3235          ipha->ipha_dst = dst = oipha->ipha_dst;
3251 3236  
3252 3237          /*
3253 3238           * If there is no option to process return now.
3254 3239           */
3255 3240          ip_hdr_length = IP_SIMPLE_HDR_LENGTH;
3256 3241  
3257 3242          if (V_HLEN == IP_SIMPLE_HDR_VERSION) {
3258 3243                  /* Form the AH header */
3259 3244                  goto ah_hdr;
3260 3245          }
3261 3246  
3262 3247          ip_hdr_length += option_length;
3263 3248  
3264 3249          /*
3265 3250           * We have options. In the outbound case for source route,
3266 3251           * ULP has already moved the first hop, which is now in
3267 3252           * ipha_dst. We need the final destination for the calculation
3268 3253           * of authentication data. And also make sure that mutable
3269 3254           * and experimental fields are zeroed out in the IP options.
3270 3255           */
3271 3256  
3272 3257          bcopy(&oipha[1], &ipha[1], option_length);
3273 3258  
3274 3259          for (optval = ipoptp_first(&opts, ipha);
3275 3260              optval != IPOPT_EOL;
3276 3261              optval = ipoptp_next(&opts)) {
3277 3262                  optptr = opts.ipoptp_cur;
3278 3263                  optlen = opts.ipoptp_len;
3279 3264                  switch (optval) {
3280 3265                  case IPOPT_EXTSEC:
3281 3266                  case IPOPT_COMSEC:
3282 3267                  case IPOPT_RA:
3283 3268                  case IPOPT_SDMDD:
3284 3269                  case IPOPT_SECURITY:
3285 3270                          /*
3286 3271                           * These options are Immutable, leave them as-is.
3287 3272                           * Note that IPOPT_NOP is also Immutable, but it
3288 3273                           * was skipped by ipoptp_next() and thus remains
3289 3274                           * intact in the header.
3290 3275                           */
3291 3276                          break;
3292 3277                  case IPOPT_SSRR:
3293 3278                  case IPOPT_LSRR:
3294 3279                          if ((opts.ipoptp_flags & IPOPTP_ERROR) != 0)
3295 3280                                  goto bad_ipv4opt;
3296 3281                          /*
3297 3282                           * These two are mutable and will be zeroed, but
3298 3283                           * first get the final destination.
3299 3284                           */
3300 3285                          off = optptr[IPOPT_OFFSET];
3301 3286                          /*
3302 3287                           * If one of the conditions is true, it means
3303 3288                           * end of options and dst already has the right
3304 3289                           * value. So, just fall through.
3305 3290                           */
3306 3291                          if (!(optlen < IP_ADDR_LEN || off > optlen - 3)) {
3307 3292                                  off = optlen - IP_ADDR_LEN;
3308 3293                                  bcopy(&optptr[off], &dst, IP_ADDR_LEN);
3309 3294                          }
3310 3295                          /* FALLTHRU */
3311 3296                  case IPOPT_RR:
3312 3297                  case IPOPT_TS:
3313 3298                  case IPOPT_SATID:
3314 3299                  default:
3315 3300                          /*
3316 3301                           * optlen should include from the beginning of an
3317 3302                           * option.
3318 3303                           * NOTE : Stream Identifier Option (SID): RFC 791
3319 3304                           * shows the bit pattern of optlen as 2 and documents
3320 3305                           * the length as 4. We assume it to be 2 here.
3321 3306                           */
3322 3307                          bzero(optptr, optlen);
3323 3308                          break;
3324 3309                  }
3325 3310          }
3326 3311  
3327 3312          if ((opts.ipoptp_flags & IPOPTP_ERROR) != 0) {
3328 3313  bad_ipv4opt:
3329 3314                  ah1dbg(ahstack, ("AH : bad IPv4 option"));
3330 3315                  freeb(phdr_mp);
3331 3316                  return (NULL);
3332 3317          }
3333 3318  
3334 3319          /*
3335 3320           * Don't change ipha_dst for an inbound datagram as it points
3336 3321           * to the right value. Only for the outbound with LSRR/SSRR,
3337 3322           * because of ip_massage_options called by the ULP, ipha_dst
3338 3323           * points to the first hop and we need to use the final
3339 3324           * destination for computing the ICV.
3340 3325           */
3341 3326  
3342 3327          if (outbound)
3343 3328                  ipha->ipha_dst = dst;
3344 3329  ah_hdr:
3345 3330          ((ah_t *)((uint8_t *)ipha + ip_hdr_length))->ah_nexthdr =
3346 3331              oipha->ipha_protocol;
3347 3332          if (!ah_finish_up(((ah_t *)((uint8_t *)ipha + ip_hdr_length)),
3348 3333              (outbound ? NULL : ((ah_t *)((uint8_t *)oipha + ip_hdr_length))),
3349 3334              assoc, ah_data_sz, ah_align_sz, ahstack)) {
3350 3335                  freeb(phdr_mp);
3351 3336                  /*
3352 3337                   * Returning NULL will tell the caller to IPSA_REFELE(), free
3353 3338                   * the memory, etc.
3354 3339                   */
3355 3340                  return (NULL);
3356 3341          }
3357 3342  
3358 3343          phdr_mp->b_wptr = ((uchar_t *)ipha + ip_hdr_length +
3359 3344              sizeof (ah_t) + ah_align_sz);
3360 3345  
3361 3346          ASSERT(phdr_mp->b_wptr <= phdr_mp->b_datap->db_lim);
3362 3347          if (outbound)
3363 3348                  *length_to_skip = ip_hdr_length;
3364 3349          else
3365 3350                  *length_to_skip = ip_hdr_length + sizeof (ah_t) + ah_align_sz;
3366 3351          return (phdr_mp);
3367 3352  }
3368 3353  
3369 3354  /*
3370 3355   * Authenticate an outbound datagram. This function is called
3371 3356   * whenever IP sends an outbound datagram that needs authentication.
3372 3357   * Returns a modified packet if done. Returns NULL if error or queued.
3373 3358   * If error return then ipIfStatsOutDiscards has been increased.
3374 3359   */
3375 3360  static mblk_t *
3376 3361  ah_outbound(mblk_t *data_mp, ip_xmit_attr_t *ixa)
3377 3362  {
3378 3363          mblk_t *phdr_mp;
3379 3364          ipsa_t *assoc;
3380 3365          int length_to_skip;
3381 3366          uint_t ah_align_sz;
3382 3367          uint_t age_bytes;
3383 3368          netstack_t      *ns = ixa->ixa_ipst->ips_netstack;
3384 3369          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
3385 3370          ipsec_stack_t   *ipss = ns->netstack_ipsec;
3386 3371          ill_t           *ill = ixa->ixa_nce->nce_ill;
3387 3372          boolean_t       need_refrele = B_FALSE;
3388 3373  
3389 3374          /*
3390 3375           * Construct the chain of mblks
3391 3376           *
3392 3377           * PSEUDO_HDR->DATA
3393 3378           *
3394 3379           * one by one.
3395 3380           */
3396 3381  
3397 3382          AH_BUMP_STAT(ahstack, out_requests);
3398 3383  
3399 3384          ASSERT(data_mp->b_datap->db_type == M_DATA);
3400 3385  
3401 3386          assoc = ixa->ixa_ipsec_ah_sa;
3402 3387          ASSERT(assoc != NULL);
3403 3388  
3404 3389  
3405 3390          /*
3406 3391           * Get the outer IP header in shape to escape this system..
3407 3392           */
3408 3393          if (is_system_labeled() && (assoc->ipsa_otsl != NULL)) {
3409 3394                  /*
3410 3395                   * Need to update packet with any CIPSO option and update
3411 3396                   * ixa_tsl to capture the new label.
3412 3397                   * We allocate a separate ixa for that purpose.
3413 3398                   */
3414 3399                  ixa = ip_xmit_attr_duplicate(ixa);
3415 3400                  if (ixa == NULL) {
3416 3401                          ip_drop_packet(data_mp, B_FALSE, ill,
3417 3402                              DROPPER(ipss, ipds_ah_nomem),
3418 3403                              &ahstack->ah_dropper);
3419 3404                          return (NULL);
3420 3405                  }
3421 3406                  need_refrele = B_TRUE;
3422 3407  
3423 3408                  label_hold(assoc->ipsa_otsl);
3424 3409                  ip_xmit_attr_replace_tsl(ixa, assoc->ipsa_otsl);
3425 3410  
3426 3411                  data_mp = sadb_whack_label(data_mp, assoc, ixa,
3427 3412                      DROPPER(ipss, ipds_ah_nomem), &ahstack->ah_dropper);
3428 3413                  if (data_mp == NULL) {
3429 3414                          /* Packet dropped by sadb_whack_label */
3430 3415                          ixa_refrele(ixa);
3431 3416                          return (NULL);
3432 3417                  }
3433 3418          }
3434 3419  
3435 3420          /*
3436 3421           * Age SA according to number of bytes that will be sent after
3437 3422           * adding the AH header, ICV, and padding to the packet.
3438 3423           */
3439 3424  
3440 3425          if (ixa->ixa_flags & IXAF_IS_IPV4) {
3441 3426                  ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
3442 3427                  ah_align_sz = P2ALIGN(assoc->ipsa_mac_len +
3443 3428                      IPV4_PADDING_ALIGN - 1, IPV4_PADDING_ALIGN);
3444 3429                  age_bytes = ntohs(ipha->ipha_length) + sizeof (ah_t) +
3445 3430                      ah_align_sz;
3446 3431          } else {
3447 3432                  ip6_t *ip6h = (ip6_t *)data_mp->b_rptr;
3448 3433                  ah_align_sz = P2ALIGN(assoc->ipsa_mac_len +
3449 3434                      IPV6_PADDING_ALIGN - 1, IPV6_PADDING_ALIGN);
3450 3435                  age_bytes = sizeof (ip6_t) + ntohs(ip6h->ip6_plen) +
3451 3436                      sizeof (ah_t) + ah_align_sz;
3452 3437          }
3453 3438  
3454 3439          if (!ah_age_bytes(assoc, age_bytes, B_FALSE)) {
3455 3440                  /* rig things as if ipsec_getassocbyconn() failed */
3456 3441                  ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
3457 3442                      "AH association 0x%x, dst %s had bytes expire.\n",
3458 3443                      ntohl(assoc->ipsa_spi), assoc->ipsa_dstaddr, AF_INET,
3459 3444                      ahstack->ipsecah_netstack);
3460 3445                  BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
3461 3446                  ip_drop_output("ipIfStatsOutDiscards", data_mp, ill);
3462 3447                  freemsg(data_mp);
3463 3448                  if (need_refrele)
3464 3449                          ixa_refrele(ixa);
3465 3450                  return (NULL);
3466 3451          }
3467 3452  
3468 3453          /*
3469 3454           * XXX We need to have fixed up the outer label before we get here.
3470 3455           * (AH is computing the checksum over the outer label).
3471 3456           */
3472 3457  
3473 3458          /*
3474 3459           * Insert pseudo header:
3475 3460           * [IP, ULP] => [IP, AH, ICV] -> ULP
3476 3461           */
3477 3462  
3478 3463          if (ixa->ixa_flags & IXAF_IS_IPV4) {
3479 3464                  phdr_mp = ah_process_ip_options_v4(data_mp, assoc,
3480 3465                      &length_to_skip, assoc->ipsa_mac_len, B_TRUE, ahstack);
3481 3466          } else {
3482 3467                  phdr_mp = ah_process_ip_options_v6(data_mp, assoc,
3483 3468                      &length_to_skip, assoc->ipsa_mac_len, B_TRUE, ahstack);
3484 3469          }
3485 3470  
3486 3471          if (phdr_mp == NULL) {
3487 3472                  AH_BUMP_STAT(ahstack, out_discards);
3488 3473                  ip_drop_packet(data_mp, B_FALSE, ixa->ixa_nce->nce_ill,
3489 3474                      DROPPER(ipss, ipds_ah_bad_v4_opts),
3490 3475                      &ahstack->ah_dropper);
3491 3476                  BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
3492 3477                  if (need_refrele)
3493 3478                          ixa_refrele(ixa);
3494 3479                  return (NULL);
3495 3480          }
3496 3481  
3497 3482          phdr_mp->b_cont = data_mp;
3498 3483          data_mp->b_rptr += length_to_skip;
3499 3484          data_mp = phdr_mp;
3500 3485  
3501 3486          /*
3502 3487           * At this point data_mp points to
3503 3488           * an mblk containing the pseudo header (IP header,
3504 3489           * AH header, and ICV with mutable fields zero'ed out).
3505 3490           * mp points to the mblk containing the ULP data. The original
3506 3491           * IP header is kept before the ULP data in data_mp.
3507 3492           */
3508 3493  
3509 3494          /* submit MAC request to KCF */
3510 3495          data_mp = ah_submit_req_outbound(data_mp, ixa, length_to_skip, assoc);
3511 3496          if (need_refrele)
3512 3497                  ixa_refrele(ixa);
3513 3498          return (data_mp);
3514 3499  }
3515 3500  
3516 3501  static mblk_t *
3517 3502  ah_inbound(mblk_t *data_mp, void *arg, ip_recv_attr_t *ira)
3518 3503  {
3519 3504          ah_t            *ah = (ah_t *)arg;
3520 3505          ipsa_t          *assoc = ira->ira_ipsec_ah_sa;
3521 3506          int             length_to_skip;
3522 3507          int             ah_length;
3523 3508          mblk_t          *phdr_mp;
3524 3509          uint32_t        ah_offset;
3525 3510          netstack_t      *ns = ira->ira_ill->ill_ipst->ips_netstack;
3526 3511          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
3527 3512          ipsec_stack_t   *ipss = ns->netstack_ipsec;
3528 3513  
3529 3514          ASSERT(assoc != NULL);
3530 3515  
3531 3516          /*
3532 3517           * We may wish to check replay in-range-only here as an optimization.
3533 3518           * Include the reality check of ipsa->ipsa_replay >
3534 3519           * ipsa->ipsa_replay_wsize for times when it's the first N packets,
3535 3520           * where N == ipsa->ipsa_replay_wsize.
3536 3521           *
3537 3522           * Another check that may come here later is the "collision" check.
3538 3523           * If legitimate packets flow quickly enough, this won't be a problem,
3539 3524           * but collisions may cause authentication algorithm crunching to
3540 3525           * take place when it doesn't need to.
3541 3526           */
3542 3527          if (!sadb_replay_peek(assoc, ah->ah_replay)) {
3543 3528                  AH_BUMP_STAT(ahstack, replay_early_failures);
3544 3529                  IP_AH_BUMP_STAT(ipss, in_discards);
3545 3530                  ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
3546 3531                      DROPPER(ipss, ipds_ah_early_replay),
3547 3532                      &ahstack->ah_dropper);
3548 3533                  BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
3549 3534                  return (NULL);
3550 3535          }
3551 3536  
3552 3537          /*
3553 3538           * The offset of the AH header can be computed from its pointer
3554 3539           * within the data mblk, which was pulled up until the AH header
3555 3540           * by ipsec_inbound_ah_sa() during SA selection.
3556 3541           */
3557 3542          ah_offset = (uchar_t *)ah - data_mp->b_rptr;
3558 3543  
3559 3544          /*
3560 3545           * We need to pullup until the ICV before we call
3561 3546           * ah_process_ip_options_v6.
3562 3547           */
3563 3548          ah_length = (ah->ah_length << 2) + 8;
3564 3549  
3565 3550          /*
3566 3551           * NOTE : If we want to use any field of IP/AH header, you need
3567 3552           * to re-assign following the pullup.
3568 3553           */
3569 3554          if (((uchar_t *)ah + ah_length) > data_mp->b_wptr) {
3570 3555                  if (!pullupmsg(data_mp, (uchar_t *)ah + ah_length -
3571 3556                      data_mp->b_rptr)) {
3572 3557                          (void) ipsec_rl_strlog(ns, info.mi_idnum, 0, 0,
3573 3558                              SL_WARN | SL_ERROR,
3574 3559                              "ah_inbound: Small AH header\n");
3575 3560                          IP_AH_BUMP_STAT(ipss, in_discards);
3576 3561                          ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
3577 3562                              DROPPER(ipss, ipds_ah_nomem),
3578 3563                              &ahstack->ah_dropper);
3579 3564                          BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
3580 3565                          return (NULL);
3581 3566                  }
3582 3567          }
3583 3568  
3584 3569          /*
3585 3570           * Insert pseudo header:
3586 3571           * [IP, ULP] => [IP, AH, ICV] -> ULP
3587 3572           */
3588 3573          if (ira->ira_flags & IRAF_IS_IPV4) {
3589 3574                  phdr_mp = ah_process_ip_options_v4(data_mp, assoc,
3590 3575                      &length_to_skip, assoc->ipsa_mac_len, B_FALSE, ahstack);
3591 3576          } else {
3592 3577                  phdr_mp = ah_process_ip_options_v6(data_mp, assoc,
3593 3578                      &length_to_skip, assoc->ipsa_mac_len, B_FALSE, ahstack);
3594 3579          }
3595 3580  
3596 3581          if (phdr_mp == NULL) {
3597 3582                  IP_AH_BUMP_STAT(ipss, in_discards);
3598 3583                  ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
3599 3584                      ((ira->ira_flags & IRAF_IS_IPV4) ?
3600 3585                      DROPPER(ipss, ipds_ah_bad_v4_opts) :
3601 3586                      DROPPER(ipss, ipds_ah_bad_v6_hdrs)),
3602 3587                      &ahstack->ah_dropper);
3603 3588                  BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
3604 3589                  return (NULL);
3605 3590          }
3606 3591  
3607 3592          phdr_mp->b_cont = data_mp;
3608 3593          data_mp->b_rptr += length_to_skip;
3609 3594          data_mp = phdr_mp;
3610 3595  
3611 3596          /* submit request to KCF */
3612 3597          return (ah_submit_req_inbound(data_mp, ira, length_to_skip, ah_offset,
3613 3598              assoc));
3614 3599  }
3615 3600  
3616 3601  /*
3617 3602   * Invoked after processing of an inbound packet by the
3618 3603   * kernel crypto framework. Called by ah_submit_req() for a sync request,
3619 3604   * or by the kcf callback for an async request.
3620 3605   * Returns NULL if the mblk chain is consumed.
3621 3606   */
3622 3607  static mblk_t *
3623 3608  ah_auth_in_done(mblk_t *phdr_mp, ip_recv_attr_t *ira, ipsec_crypto_t *ic)
3624 3609  {
3625 3610          ipha_t *ipha;
3626 3611          uint_t ah_offset = 0;
3627 3612          mblk_t *mp;
3628 3613          int align_len, newpos;
3629 3614          ah_t *ah;
3630 3615          uint32_t length;
3631 3616          uint32_t *dest32;
3632 3617          uint8_t *dest;
3633 3618          boolean_t isv4;
3634 3619          ip6_t *ip6h;
3635 3620          uint_t icv_len;
3636 3621          ipsa_t *assoc;
3637 3622          kstat_named_t *counter;
3638 3623          netstack_t      *ns = ira->ira_ill->ill_ipst->ips_netstack;
3639 3624          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
3640 3625          ipsec_stack_t   *ipss = ns->netstack_ipsec;
3641 3626  
3642 3627          isv4 = (ira->ira_flags & IRAF_IS_IPV4);
3643 3628          assoc = ira->ira_ipsec_ah_sa;
3644 3629          icv_len = (uint_t)ic->ic_crypto_mac.cd_raw.iov_len;
3645 3630  
3646 3631          if (phdr_mp == NULL) {
3647 3632                  ip_drop_packet(phdr_mp, B_TRUE, ira->ira_ill,
3648 3633                      DROPPER(ipss, ipds_ah_nomem),
3649 3634                      &ahstack->ah_dropper);
3650 3635                  BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
3651 3636                  return (NULL);
3652 3637          }
3653 3638  
3654 3639          mp = phdr_mp->b_cont;
3655 3640          if (mp == NULL) {
3656 3641                  ip_drop_packet(phdr_mp, B_TRUE, ira->ira_ill,
3657 3642                      DROPPER(ipss, ipds_ah_nomem),
3658 3643                      &ahstack->ah_dropper);
3659 3644                  BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
3660 3645                  return (NULL);
3661 3646          }
3662 3647          mp->b_rptr -= ic->ic_skip_len;
3663 3648  
3664 3649          ah_set_usetime(assoc, B_TRUE);
3665 3650  
3666 3651          if (isv4) {
3667 3652                  ipha = (ipha_t *)mp->b_rptr;
3668 3653                  ah_offset = ipha->ipha_version_and_hdr_length -
3669 3654                      (uint8_t)((IP_VERSION << 4));
3670 3655                  ah_offset <<= 2;
3671 3656                  align_len = P2ALIGN(icv_len + IPV4_PADDING_ALIGN - 1,
3672 3657                      IPV4_PADDING_ALIGN);
3673 3658          } else {
3674 3659                  ip6h = (ip6_t *)mp->b_rptr;
3675 3660                  ah_offset = ipsec_ah_get_hdr_size_v6(mp, B_TRUE);
3676 3661                  ASSERT((mp->b_wptr - mp->b_rptr) >= ah_offset);
3677 3662                  align_len = P2ALIGN(icv_len + IPV6_PADDING_ALIGN - 1,
3678 3663                      IPV6_PADDING_ALIGN);
3679 3664          }
3680 3665  
3681 3666          ah = (ah_t *)(mp->b_rptr + ah_offset);
3682 3667          newpos = sizeof (ah_t) + align_len;
3683 3668  
3684 3669          /*
3685 3670           * We get here only when authentication passed.
3686 3671           */
3687 3672  
3688 3673          ah3dbg(ahstack, ("AH succeeded, checking replay\n"));
3689 3674          AH_BUMP_STAT(ahstack, good_auth);
3690 3675  
3691 3676          if (!sadb_replay_check(assoc, ah->ah_replay)) {
3692 3677                  int af;
3693 3678                  void *addr;
3694 3679  
3695 3680                  if (isv4) {
3696 3681                          addr = &ipha->ipha_dst;
3697 3682                          af = AF_INET;
3698 3683                  } else {
3699 3684                          addr = &ip6h->ip6_dst;
3700 3685                          af = AF_INET6;
3701 3686                  }
3702 3687  
3703 3688                  /*
3704 3689                   * Log the event. As of now we print out an event.
3705 3690                   * Do not print the replay failure number, or else
3706 3691                   * syslog cannot collate the error messages.  Printing
3707 3692                   * the replay number that failed (or printing to the
3708 3693                   * console) opens a denial-of-service attack.
3709 3694                   */
3710 3695                  AH_BUMP_STAT(ahstack, replay_failures);
3711 3696                  ipsec_assocfailure(info.mi_idnum, 0, 0,
3712 3697                      SL_ERROR | SL_WARN,
3713 3698                      "Replay failed for AH spi %x, dst_addr %s",
3714 3699                      assoc->ipsa_spi, addr, af, ahstack->ipsecah_netstack);
3715 3700                  counter = DROPPER(ipss, ipds_ah_replay);
3716 3701                  goto ah_in_discard;
3717 3702          }
3718 3703  
3719 3704          /*
3720 3705           * We need to remove the AH header from the original
3721 3706           * datagram. Best way to do this is to move the pre-AH headers
3722 3707           * forward in the (relatively simple) IPv4 case.  In IPv6, it's
3723 3708           * a bit more complicated because of IPv6's next-header chaining,
3724 3709           * but it's doable.
3725 3710           */
3726 3711          if (isv4) {
3727 3712                  /*
3728 3713                   * Assign the right protocol, adjust the length as we
3729 3714                   * are removing the AH header and adjust the checksum to
3730 3715                   * account for the protocol and length.
3731 3716                   */
3732 3717                  length = ntohs(ipha->ipha_length);
3733 3718                  if (!ah_age_bytes(assoc, length, B_TRUE)) {
3734 3719                          /* The ipsa has hit hard expiration, LOG and AUDIT. */
3735 3720                          ipsec_assocfailure(info.mi_idnum, 0, 0,
3736 3721                              SL_ERROR | SL_WARN,
3737 3722                              "AH Association 0x%x, dst %s had bytes expire.\n",
3738 3723                              assoc->ipsa_spi, assoc->ipsa_dstaddr,
3739 3724                              AF_INET, ahstack->ipsecah_netstack);
3740 3725                          AH_BUMP_STAT(ahstack, bytes_expired);
3741 3726                          counter = DROPPER(ipss, ipds_ah_bytes_expire);
3742 3727                          goto ah_in_discard;
3743 3728                  }
3744 3729                  ipha->ipha_protocol = ah->ah_nexthdr;
3745 3730                  length -= newpos;
3746 3731  
3747 3732                  ipha->ipha_length = htons((uint16_t)length);
3748 3733                  ipha->ipha_hdr_checksum = 0;
3749 3734                  ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha);
3750 3735          } else {
3751 3736                  uchar_t *whereptr;
3752 3737                  int hdrlen;
3753 3738                  uint8_t *nexthdr;
3754 3739                  ip6_hbh_t *hbhhdr;
3755 3740                  ip6_dest_t *dsthdr;
3756 3741                  ip6_rthdr0_t *rthdr;
3757 3742  
3758 3743                  /*
3759 3744                   * Make phdr_mp hold until the AH header and make
3760 3745                   * mp hold everything past AH header.
3761 3746                   */
3762 3747                  length = ntohs(ip6h->ip6_plen);
3763 3748                  if (!ah_age_bytes(assoc, length + sizeof (ip6_t), B_TRUE)) {
3764 3749                          /* The ipsa has hit hard expiration, LOG and AUDIT. */
3765 3750                          ipsec_assocfailure(info.mi_idnum, 0, 0,
3766 3751                              SL_ERROR | SL_WARN,
3767 3752                              "AH Association 0x%x, dst %s had bytes "
3768 3753                              "expire.\n", assoc->ipsa_spi, &ip6h->ip6_dst,
3769 3754                              AF_INET6, ahstack->ipsecah_netstack);
3770 3755                          AH_BUMP_STAT(ahstack, bytes_expired);
3771 3756                          counter = DROPPER(ipss, ipds_ah_bytes_expire);
3772 3757                          goto ah_in_discard;
3773 3758                  }
3774 3759  
3775 3760                  /*
3776 3761                   * Update the next header field of the header preceding
3777 3762                   * AH with the next header field of AH. Start with the
3778 3763                   * IPv6 header and proceed with the extension headers
3779 3764                   * until we find what we're looking for.
3780 3765                   */
3781 3766                  nexthdr = &ip6h->ip6_nxt;
3782 3767                  whereptr =  (uchar_t *)ip6h;
3783 3768                  hdrlen = sizeof (ip6_t);
3784 3769  
3785 3770                  while (*nexthdr != IPPROTO_AH) {
3786 3771                          whereptr += hdrlen;
3787 3772                          /* Assume IP has already stripped it */
3788 3773                          ASSERT(*nexthdr != IPPROTO_FRAGMENT);
3789 3774                          switch (*nexthdr) {
3790 3775                          case IPPROTO_HOPOPTS:
3791 3776                                  hbhhdr = (ip6_hbh_t *)whereptr;
3792 3777                                  nexthdr = &hbhhdr->ip6h_nxt;
3793 3778                                  hdrlen = 8 * (hbhhdr->ip6h_len + 1);
3794 3779                                  break;
3795 3780                          case IPPROTO_DSTOPTS:
3796 3781                                  dsthdr = (ip6_dest_t *)whereptr;
3797 3782                                  nexthdr = &dsthdr->ip6d_nxt;
3798 3783                                  hdrlen = 8 * (dsthdr->ip6d_len + 1);
3799 3784                                  break;
3800 3785                          case IPPROTO_ROUTING:
3801 3786                                  rthdr = (ip6_rthdr0_t *)whereptr;
3802 3787                                  nexthdr = &rthdr->ip6r0_nxt;
3803 3788                                  hdrlen = 8 * (rthdr->ip6r0_len + 1);
3804 3789                                  break;
3805 3790                          }
3806 3791                  }
3807 3792                  *nexthdr = ah->ah_nexthdr;
3808 3793                  length -= newpos;
3809 3794                  ip6h->ip6_plen = htons((uint16_t)length);
3810 3795          }
3811 3796  
3812 3797          /* Now that we've fixed the IP header, move it forward. */
3813 3798          mp->b_rptr += newpos;
3814 3799          if (IS_P2ALIGNED(mp->b_rptr, sizeof (uint32_t))) {
3815 3800                  dest32 = (uint32_t *)(mp->b_rptr + ah_offset);
3816 3801                  while (--dest32 >= (uint32_t *)mp->b_rptr)
3817 3802                          *dest32 = *(dest32 - (newpos >> 2));
3818 3803          } else {
3819 3804                  dest = mp->b_rptr + ah_offset;
3820 3805                  while (--dest >= mp->b_rptr)
3821 3806                          *dest = *(dest - newpos);
3822 3807          }
3823 3808          freeb(phdr_mp);
3824 3809  
3825 3810          /*
3826 3811           * If SA is labelled, use its label, else inherit the label
  
    | 
      ↓ open down ↓ | 
    1903 lines elided | 
    
      ↑ open up ↑ | 
  
3827 3812           */
3828 3813          if (is_system_labeled() && (assoc->ipsa_tsl != NULL)) {
3829 3814                  if (!ip_recv_attr_replace_label(ira, assoc->ipsa_tsl)) {
3830 3815                          ip_drop_packet(mp, B_TRUE, ira->ira_ill,
3831 3816                              DROPPER(ipss, ipds_ah_nomem), &ahstack->ah_dropper);
3832 3817                          BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
3833 3818                          return (NULL);
3834 3819                  }
3835 3820          }
3836 3821  
3837      -        if (assoc->ipsa_state == IPSA_STATE_IDLE) {
3838      -                /*
3839      -                 * Cluster buffering case.  Tell caller that we're
3840      -                 * handling the packet.
3841      -                 */
3842      -                sadb_buf_pkt(assoc, mp, ira);
3843      -                return (NULL);
3844      -        }
3845      -
3846 3822          return (mp);
3847 3823  
3848 3824  ah_in_discard:
3849 3825          IP_AH_BUMP_STAT(ipss, in_discards);
3850 3826          ip_drop_packet(phdr_mp, B_TRUE, ira->ira_ill, counter,
3851 3827              &ahstack->ah_dropper);
3852 3828          BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
3853 3829          return (NULL);
3854 3830  }
3855 3831  
3856 3832  /*
3857 3833   * Invoked after processing of an outbound packet by the
3858 3834   * kernel crypto framework, either by ah_submit_req() for a request
3859 3835   * executed syncrhonously, or by the KEF callback for a request
3860 3836   * executed asynchronously.
3861 3837   */
3862 3838  static mblk_t *
3863 3839  ah_auth_out_done(mblk_t *phdr_mp, ip_xmit_attr_t *ixa, ipsec_crypto_t *ic)
3864 3840  {
3865 3841          mblk_t *mp;
3866 3842          int align_len;
3867 3843          uint32_t hdrs_length;
3868 3844          uchar_t *ptr;
3869 3845          uint32_t length;
3870 3846          boolean_t isv4;
3871 3847          size_t icv_len;
3872 3848          netstack_t      *ns = ixa->ixa_ipst->ips_netstack;
3873 3849          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
3874 3850          ipsec_stack_t   *ipss = ns->netstack_ipsec;
3875 3851          ill_t           *ill = ixa->ixa_nce->nce_ill;
3876 3852  
3877 3853          isv4 = (ixa->ixa_flags & IXAF_IS_IPV4);
3878 3854          icv_len = ic->ic_crypto_mac.cd_raw.iov_len;
3879 3855  
3880 3856          mp = phdr_mp->b_cont;
3881 3857          if (mp == NULL) {
3882 3858                  ip_drop_packet(phdr_mp, B_FALSE, ill,
3883 3859                      DROPPER(ipss, ipds_ah_nomem),
3884 3860                      &ahstack->ah_dropper);
3885 3861                  BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
3886 3862                  return (NULL);
3887 3863          }
3888 3864          mp->b_rptr -= ic->ic_skip_len;
3889 3865  
3890 3866          ASSERT(ixa->ixa_flags & IXAF_IPSEC_SECURE);
3891 3867          ASSERT(ixa->ixa_ipsec_ah_sa != NULL);
3892 3868          ah_set_usetime(ixa->ixa_ipsec_ah_sa, B_FALSE);
3893 3869  
3894 3870          if (isv4) {
3895 3871                  ipha_t *ipha;
3896 3872                  ipha_t *nipha;
3897 3873  
3898 3874                  ipha = (ipha_t *)mp->b_rptr;
3899 3875                  hdrs_length = ipha->ipha_version_and_hdr_length -
3900 3876                      (uint8_t)((IP_VERSION << 4));
3901 3877                  hdrs_length <<= 2;
3902 3878                  align_len = P2ALIGN(icv_len + IPV4_PADDING_ALIGN - 1,
3903 3879                      IPV4_PADDING_ALIGN);
3904 3880                  /*
3905 3881                   * phdr_mp must have the right amount of space for the
3906 3882                   * combined IP and AH header. Copy the IP header and
3907 3883                   * the ack_data onto AH. Note that the AH header was
3908 3884                   * already formed before the ICV calculation and hence
3909 3885                   * you don't have to copy it here.
3910 3886                   */
3911 3887                  bcopy(mp->b_rptr, phdr_mp->b_rptr, hdrs_length);
3912 3888  
3913 3889                  ptr = phdr_mp->b_rptr + hdrs_length + sizeof (ah_t);
3914 3890                  bcopy(phdr_mp->b_wptr, ptr, icv_len);
3915 3891  
3916 3892                  /*
3917 3893                   * Compute the new header checksum as we are assigning
3918 3894                   * IPPROTO_AH and adjusting the length here.
3919 3895                   */
3920 3896                  nipha = (ipha_t *)phdr_mp->b_rptr;
3921 3897  
3922 3898                  nipha->ipha_protocol = IPPROTO_AH;
3923 3899                  length = ntohs(nipha->ipha_length);
3924 3900                  length += (sizeof (ah_t) + align_len);
3925 3901                  nipha->ipha_length = htons((uint16_t)length);
3926 3902                  nipha->ipha_hdr_checksum = 0;
3927 3903                  nipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(nipha);
3928 3904          } else {
3929 3905                  ip6_t *ip6h;
3930 3906                  ip6_t *nip6h;
3931 3907                  uint_t ah_offset;
3932 3908  
3933 3909                  ip6h = (ip6_t *)mp->b_rptr;
3934 3910                  nip6h = (ip6_t *)phdr_mp->b_rptr;
3935 3911                  align_len = P2ALIGN(icv_len + IPV6_PADDING_ALIGN - 1,
3936 3912                      IPV6_PADDING_ALIGN);
3937 3913                  /*
3938 3914                   * phdr_mp must have the right amount of space for the
3939 3915                   * combined IP and AH header. Copy the IP header with
3940 3916                   * options into the pseudo header. When we constructed
3941 3917                   * a pseudo header, we did not copy some of the mutable
3942 3918                   * fields. We do it now by calling ah_fix_phdr_v6()
3943 3919                   * with the last argument B_TRUE. It returns the
3944 3920                   * ah_offset into the pseudo header.
3945 3921                   */
3946 3922  
3947 3923                  bcopy(ip6h, nip6h, IPV6_HDR_LEN);
3948 3924                  ah_offset = ah_fix_phdr_v6(nip6h, ip6h, B_TRUE, B_TRUE);
3949 3925                  ASSERT(ah_offset != 0);
3950 3926                  /*
3951 3927                   * phdr_mp can hold exactly the whole IP header with options
3952 3928                   * plus the AH header also. Thus subtracting the AH header's
3953 3929                   * size should give exactly how much of the original header
3954 3930                   * should be skipped.
3955 3931                   */
3956 3932                  hdrs_length = (phdr_mp->b_wptr - phdr_mp->b_rptr) -
3957 3933                      sizeof (ah_t) - icv_len;
3958 3934                  bcopy(phdr_mp->b_wptr, ((uint8_t *)nip6h + ah_offset +
3959 3935                      sizeof (ah_t)), icv_len);
3960 3936                  length = ntohs(nip6h->ip6_plen);
3961 3937                  length += (sizeof (ah_t) + align_len);
3962 3938                  nip6h->ip6_plen = htons((uint16_t)length);
3963 3939          }
3964 3940  
3965 3941          /* Skip the original IP header */
3966 3942          mp->b_rptr += hdrs_length;
3967 3943          if (mp->b_rptr == mp->b_wptr) {
3968 3944                  phdr_mp->b_cont = mp->b_cont;
3969 3945                  freeb(mp);
3970 3946          }
3971 3947  
3972 3948          return (phdr_mp);
3973 3949  }
3974 3950  
3975 3951  /* Refactor me */
3976 3952  /*
3977 3953   * Wrapper to allow IP to trigger an AH association failure message
3978 3954   * during SA inbound selection.
3979 3955   */
3980 3956  void
3981 3957  ipsecah_in_assocfailure(mblk_t *mp, char level, ushort_t sl, char *fmt,
3982 3958      uint32_t spi, void *addr, int af, ip_recv_attr_t *ira)
3983 3959  {
3984 3960          netstack_t      *ns = ira->ira_ill->ill_ipst->ips_netstack;
3985 3961          ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
3986 3962          ipsec_stack_t   *ipss = ns->netstack_ipsec;
3987 3963  
3988 3964          if (ahstack->ipsecah_log_unknown_spi) {
3989 3965                  ipsec_assocfailure(info.mi_idnum, 0, level, sl, fmt, spi,
3990 3966                      addr, af, ahstack->ipsecah_netstack);
3991 3967          }
3992 3968  
3993 3969          ip_drop_packet(mp, B_TRUE, ira->ira_ill,
3994 3970              DROPPER(ipss, ipds_ah_no_sa),
3995 3971              &ahstack->ah_dropper);
3996 3972  }
3997 3973  
3998 3974  /*
3999 3975   * Initialize the AH input and output processing functions.
4000 3976   */
4001 3977  void
4002 3978  ipsecah_init_funcs(ipsa_t *sa)
4003 3979  {
4004 3980          if (sa->ipsa_output_func == NULL)
4005 3981                  sa->ipsa_output_func = ah_outbound;
4006 3982          if (sa->ipsa_input_func == NULL)
4007 3983                  sa->ipsa_input_func = ah_inbound;
4008 3984  }
  
    | 
      ↓ open down ↓ | 
    153 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX