Print this page
8381 Convert ipsec_alg_lock from mutex to rwlock


 281         netstackid_t    stackid = (zoneid_t)(uintptr_t)kp->ks_private;
 282         netstack_t      *ns;
 283         ipsec_stack_t   *ipss;
 284 
 285         if ((kp == NULL) || (kp->ks_data == NULL))
 286                 return (EIO);
 287 
 288         if (rw == KSTAT_WRITE)
 289                 return (EACCES);
 290 
 291         ns = netstack_find_by_stackid(stackid);
 292         if (ns == NULL)
 293                 return (-1);
 294         ipss = ns->netstack_ipsec;
 295         if (ipss == NULL) {
 296                 netstack_rele(ns);
 297                 return (-1);
 298         }
 299         ekp = (esp_kstats_t *)kp->ks_data;
 300 
 301         mutex_enter(&ipss->ipsec_alg_lock);
 302         ekp->esp_stat_num_aalgs.value.ui64 =
 303             ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
 304         ekp->esp_stat_num_ealgs.value.ui64 =
 305             ipss->ipsec_nalgs[IPSEC_ALG_ENCR];
 306         mutex_exit(&ipss->ipsec_alg_lock);
 307 
 308         netstack_rele(ns);
 309         return (0);
 310 }
 311 
 312 #ifdef DEBUG
 313 /*
 314  * Debug routine, useful to see pre-encryption data.
 315  */
 316 static char *
 317 dump_msg(mblk_t *mp)
 318 {
 319         char tmp_str[3], tmp_line[256];
 320 
 321         while (mp != NULL) {
 322                 unsigned char *ptr;
 323 
 324                 printf("mblk address 0x%p, length %ld, db_ref %d "
 325                     "type %d, base 0x%p, lim 0x%p\n",
 326                     (void *) mp, (long)(mp->b_wptr - mp->b_rptr),


1178 
1179         /* submit the request to the crypto framework */
1180         return (esp_submit_req_inbound(data_mp, ira, ipsa,
1181             (uint8_t *)esph - data_mp->b_rptr));
1182 }
1183 
1184 /*
1185  * Perform the really difficult work of inserting the proposed situation.
1186  * Called while holding the algorithm lock.
1187  */
1188 static void
1189 esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs,
1190     netstack_t *ns)
1191 {
1192         sadb_comb_t *comb = (sadb_comb_t *)(prop + 1);
1193         ipsec_action_t *ap;
1194         ipsec_prot_t *prot;
1195         ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
1196         ipsec_stack_t   *ipss = ns->netstack_ipsec;
1197 
1198         ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
1199 
1200         prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
1201         prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t));
1202         *(uint32_t *)(&prop->sadb_prop_replay) = 0;      /* Quick zero-out! */
1203 
1204         prop->sadb_prop_replay = espstack->ipsecesp_replay_size;
1205 
1206         /*
1207          * Based upon algorithm properties, and what-not, prioritize a
1208          * proposal, based on the ordering of the ESP algorithms in the
1209          * alternatives in the policy rule or socket that was placed
1210          * in the acquire record.
1211          *
1212          * For each action in policy list
1213          *   Add combination.  If I've hit limit, return.
1214          */
1215 
1216         for (ap = acqrec->ipsacq_act; ap != NULL;
1217             ap = ap->ipa_next) {
1218                 ipsec_alginfo_t *ealg = NULL;


1308         sadb_prop_t *prop;
1309         mblk_t *pfkeymp, *msgmp;
1310         ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
1311         ipsec_stack_t   *ipss = ns->netstack_ipsec;
1312 
1313         ESP_BUMP_STAT(espstack, acquire_requests);
1314 
1315         if (espstack->esp_pfkey_q == NULL) {
1316                 mutex_exit(&acqrec->ipsacq_lock);
1317                 return;
1318         }
1319 
1320         /* Set up ACQUIRE. */
1321         pfkeymp = sadb_setup_acquire(acqrec, SADB_SATYPE_ESP,
1322             ns->netstack_ipsec);
1323         if (pfkeymp == NULL) {
1324                 esp0dbg(("sadb_setup_acquire failed.\n"));
1325                 mutex_exit(&acqrec->ipsacq_lock);
1326                 return;
1327         }
1328         ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
1329         combs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH] *
1330             ipss->ipsec_nalgs[IPSEC_ALG_ENCR];
1331         msgmp = pfkeymp->b_cont;
1332         samsg = (sadb_msg_t *)(msgmp->b_rptr);
1333 
1334         /* Insert proposal here. */
1335 
1336         prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len);
1337         esp_insert_prop(prop, acqrec, combs, ns);
1338         samsg->sadb_msg_len += prop->sadb_prop_len;
1339         msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len);
1340 
1341         mutex_exit(&ipss->ipsec_alg_lock);
1342 
1343         /*
1344          * Must mutex_exit() before sending PF_KEY message up, in
1345          * order to avoid recursive mutex_enter() if there are no registered
1346          * listeners.
1347          *
1348          * Once I've sent the message, I'm cool anyway.
1349          */
1350         mutex_exit(&acqrec->ipsacq_lock);
1351         if (extended != NULL) {
1352                 putnext(espstack->esp_pfkey_q, extended);
1353         }
1354         putnext(espstack->esp_pfkey_q, pfkeymp);
1355 }
1356 
1357 /* XXX refactor me */
1358 /*
1359  * Handle the SADB_GETSPI message.  Create a larval SA.
1360  */
1361 static void


3026 
3027         /* Allocate the KEYSOCK_OUT. */
3028         keysock_out_mp = sadb_keysock_out(serial);
3029         if (keysock_out_mp == NULL) {
3030                 esp0dbg(("esp_register_out: couldn't allocate mblk.\n"));
3031                 return (B_FALSE);
3032         }
3033 
3034         if (is_system_labeled() && (cr != NULL)) {
3035                 sens_tsl = crgetlabel(cr);
3036                 if (sens_tsl != NULL) {
3037                         sens_len = sadb_sens_len_from_label(sens_tsl);
3038                         allocsize += sens_len;
3039                 }
3040         }
3041 
3042         /*
3043          * Allocate the PF_KEY message that follows KEYSOCK_OUT.
3044          */
3045 
3046         mutex_enter(&ipss->ipsec_alg_lock);
3047         /*
3048          * Fill SADB_REGISTER message's algorithm descriptors.  Hold
3049          * down the lock while filling it.
3050          *
3051          * Return only valid algorithms, so the number of algorithms
3052          * to send up may be less than the number of algorithm entries
3053          * in the table.
3054          */
3055         authalgs = ipss->ipsec_alglists[IPSEC_ALG_AUTH];
3056         for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
3057                 if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
3058                         num_aalgs++;
3059 
3060         if (num_aalgs != 0) {
3061                 allocsize += (num_aalgs * sizeof (*saalg));
3062                 allocsize += sizeof (*sasupp_auth);
3063         }
3064         encralgs = ipss->ipsec_alglists[IPSEC_ALG_ENCR];
3065         for (num_ealgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
3066                 if (encralgs[i] != NULL && ALG_VALID(encralgs[i]))
3067                         num_ealgs++;
3068 
3069         if (num_ealgs != 0) {
3070                 allocsize += (num_ealgs * sizeof (*saalg));
3071                 allocsize += sizeof (*sasupp_encr);
3072         }
3073         keysock_out_mp->b_cont = allocb(allocsize, BPRI_HI);
3074         if (keysock_out_mp->b_cont == NULL) {
3075                 mutex_exit(&ipss->ipsec_alg_lock);
3076                 freemsg(keysock_out_mp);
3077                 return (B_FALSE);
3078         }
3079         pfkey_msg_mp = keysock_out_mp->b_cont;
3080         pfkey_msg_mp->b_wptr += allocsize;
3081 
3082         nextext = (sadb_ext_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg));
3083 
3084         if (num_aalgs != 0) {
3085                 sasupp_auth = (sadb_supported_t *)nextext;
3086                 saalg = (sadb_alg_t *)(sasupp_auth + 1);
3087 
3088                 ASSERT(((ulong_t)saalg & 0x7) == 0);
3089 
3090                 numalgs_snap = 0;
3091                 for (i = 0;
3092                     ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs));
3093                     i++) {
3094                         if (authalgs[i] == NULL || !ALG_VALID(authalgs[i]))
3095                                 continue;


3149                 }
3150                 ASSERT(numalgs_snap == num_ealgs);
3151 #ifdef DEBUG
3152                 /*
3153                  * Reality check to make sure I snagged all of the
3154                  * algorithms.
3155                  */
3156                 for (; i < IPSEC_MAX_ALGS; i++) {
3157                         if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) {
3158                                 cmn_err(CE_PANIC, "esp_register_out()! "
3159                                     "Missed ealg #%d.\n", i);
3160                         }
3161                 }
3162 #endif /* DEBUG */
3163                 nextext = (sadb_ext_t *)saalg;
3164         }
3165 
3166         current_aalgs = num_aalgs;
3167         current_ealgs = num_ealgs;
3168 
3169         mutex_exit(&ipss->ipsec_alg_lock);
3170 
3171         if (sens_tsl != NULL) {
3172                 sens = (sadb_sens_t *)nextext;
3173                 sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY,
3174                     sens_tsl, sens_len);
3175 
3176                 nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
3177         }
3178 
3179         /* Now fill the rest of the SADB_REGISTER message. */
3180 
3181         samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr;
3182         samsg->sadb_msg_version = PF_KEY_V2;
3183         samsg->sadb_msg_type = SADB_REGISTER;
3184         samsg->sadb_msg_errno = 0;
3185         samsg->sadb_msg_satype = SADB_SATYPE_ESP;
3186         samsg->sadb_msg_len = SADB_8TO64(allocsize);
3187         samsg->sadb_msg_reserved = 0;
3188         /*
3189          * Assume caller has sufficient sequence/pid number info.  If it's one


3674                     !IN6_IS_ADDR_V4MAPPED(&natt_rem6->sin6_addr)) {
3675                         *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM;
3676                         return (EINVAL);
3677                 }
3678         }
3679 
3680 
3681         /* Stuff I don't support, for now.  XXX Diagnostic? */
3682         if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL)
3683                 return (EOPNOTSUPP);
3684 
3685         if ((*diagnostic = sadb_labelchk(ksi)) != 0)
3686                 return (EINVAL);
3687 
3688         /*
3689          * XXX Policy :  I'm not checking identities at this time,
3690          * but if I did, I'd do them here, before I sent
3691          * the weak key check up to the algorithm.
3692          */
3693 
3694         mutex_enter(&ipss->ipsec_alg_lock);
3695 
3696         /*
3697          * First locate the authentication algorithm.
3698          */
3699 #ifdef IPSEC_LATENCY_TEST
3700         if (akey != NULL && assoc->sadb_sa_auth != SADB_AALG_NONE) {
3701 #else
3702         if (akey != NULL) {
3703 #endif
3704                 ipsec_alginfo_t *aalg;
3705 
3706                 aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
3707                     [assoc->sadb_sa_auth];
3708                 if (aalg == NULL || !ALG_VALID(aalg)) {
3709                         mutex_exit(&ipss->ipsec_alg_lock);
3710                         esp1dbg(espstack, ("Couldn't find auth alg #%d.\n",
3711                             assoc->sadb_sa_auth));
3712                         *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
3713                         return (EINVAL);
3714                 }
3715 
3716                 /*
3717                  * Sanity check key sizes.
3718                  * Note: It's not possible to use SADB_AALG_NONE because
3719                  * this auth_alg is not defined with ALG_FLAG_VALID. If this
3720                  * ever changes, the same check for SADB_AALG_NONE and
3721                  * a auth_key != NULL should be made here ( see below).
3722                  */
3723                 if (!ipsec_valid_key_size(akey->sadb_key_bits, aalg)) {
3724                         mutex_exit(&ipss->ipsec_alg_lock);
3725                         *diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS;
3726                         return (EINVAL);
3727                 }
3728                 ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
3729 
3730                 /* check key and fix parity if needed */
3731                 if (ipsec_check_key(aalg->alg_mech_type, akey, B_TRUE,
3732                     diagnostic) != 0) {
3733                         mutex_exit(&ipss->ipsec_alg_lock);
3734                         return (EINVAL);
3735                 }
3736         }
3737 
3738         /*
3739          * Then locate the encryption algorithm.
3740          */
3741         if (ekey != NULL) {
3742                 uint_t keybits;
3743                 ipsec_alginfo_t *ealg;
3744 
3745                 ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR]
3746                     [assoc->sadb_sa_encrypt];
3747                 if (ealg == NULL || !ALG_VALID(ealg)) {
3748                         mutex_exit(&ipss->ipsec_alg_lock);
3749                         esp1dbg(espstack, ("Couldn't find encr alg #%d.\n",
3750                             assoc->sadb_sa_encrypt));
3751                         *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG;
3752                         return (EINVAL);
3753                 }
3754 
3755                 /*
3756                  * Sanity check key sizes. If the encryption algorithm is
3757                  * SADB_EALG_NULL but the encryption key is NOT
3758                  * NULL then complain.
3759                  *
3760                  * The keying material includes salt bits if required by
3761                  * algorithm and optionally the Initial IV, check the
3762                  * length of whats left.
3763                  */
3764                 keybits = ekey->sadb_key_bits;
3765                 keybits -= ekey->sadb_key_reserved;
3766                 keybits -= SADB_8TO1(ealg->alg_saltlen);
3767                 if ((assoc->sadb_sa_encrypt == SADB_EALG_NULL) ||
3768                     (!ipsec_valid_key_size(keybits, ealg))) {
3769                         mutex_exit(&ipss->ipsec_alg_lock);
3770                         *diagnostic = SADB_X_DIAGNOSTIC_BAD_EKEYBITS;
3771                         return (EINVAL);
3772                 }
3773                 ASSERT(ealg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
3774 
3775                 /* check key */
3776                 if (ipsec_check_key(ealg->alg_mech_type, ekey, B_FALSE,
3777                     diagnostic) != 0) {
3778                         mutex_exit(&ipss->ipsec_alg_lock);
3779                         return (EINVAL);
3780                 }
3781         }
3782         mutex_exit(&ipss->ipsec_alg_lock);
3783 
3784         return (esp_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi,
3785             diagnostic, espstack));
3786 }
3787 
3788 /*
3789  * Update a security association.  Updates come in two varieties.  The first
3790  * is an update of lifetimes on a non-larval SA.  The second is an update of
3791  * a larval SA, which ends up looking a lot more like an add.
3792  */
3793 static int
3794 esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
3795     ipsecesp_stack_t *espstack, uint8_t sadb_msg_type)
3796 {
3797         sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
3798         mblk_t    *buf_pkt;
3799         int rcode;
3800 
3801         sadb_address_t *dstext =
3802             (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];




 281         netstackid_t    stackid = (zoneid_t)(uintptr_t)kp->ks_private;
 282         netstack_t      *ns;
 283         ipsec_stack_t   *ipss;
 284 
 285         if ((kp == NULL) || (kp->ks_data == NULL))
 286                 return (EIO);
 287 
 288         if (rw == KSTAT_WRITE)
 289                 return (EACCES);
 290 
 291         ns = netstack_find_by_stackid(stackid);
 292         if (ns == NULL)
 293                 return (-1);
 294         ipss = ns->netstack_ipsec;
 295         if (ipss == NULL) {
 296                 netstack_rele(ns);
 297                 return (-1);
 298         }
 299         ekp = (esp_kstats_t *)kp->ks_data;
 300 
 301         rw_enter(&ipss->ipsec_alg_lock, RW_READER);
 302         ekp->esp_stat_num_aalgs.value.ui64 =
 303             ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
 304         ekp->esp_stat_num_ealgs.value.ui64 =
 305             ipss->ipsec_nalgs[IPSEC_ALG_ENCR];
 306         rw_exit(&ipss->ipsec_alg_lock);
 307 
 308         netstack_rele(ns);
 309         return (0);
 310 }
 311 
 312 #ifdef DEBUG
 313 /*
 314  * Debug routine, useful to see pre-encryption data.
 315  */
 316 static char *
 317 dump_msg(mblk_t *mp)
 318 {
 319         char tmp_str[3], tmp_line[256];
 320 
 321         while (mp != NULL) {
 322                 unsigned char *ptr;
 323 
 324                 printf("mblk address 0x%p, length %ld, db_ref %d "
 325                     "type %d, base 0x%p, lim 0x%p\n",
 326                     (void *) mp, (long)(mp->b_wptr - mp->b_rptr),


1178 
1179         /* submit the request to the crypto framework */
1180         return (esp_submit_req_inbound(data_mp, ira, ipsa,
1181             (uint8_t *)esph - data_mp->b_rptr));
1182 }
1183 
1184 /*
1185  * Perform the really difficult work of inserting the proposed situation.
1186  * Called while holding the algorithm lock.
1187  */
1188 static void
1189 esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs,
1190     netstack_t *ns)
1191 {
1192         sadb_comb_t *comb = (sadb_comb_t *)(prop + 1);
1193         ipsec_action_t *ap;
1194         ipsec_prot_t *prot;
1195         ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
1196         ipsec_stack_t   *ipss = ns->netstack_ipsec;
1197 
1198         ASSERT(RW_READ_HELD(&ipss->ipsec_alg_lock));
1199 
1200         prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
1201         prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t));
1202         *(uint32_t *)(&prop->sadb_prop_replay) = 0;      /* Quick zero-out! */
1203 
1204         prop->sadb_prop_replay = espstack->ipsecesp_replay_size;
1205 
1206         /*
1207          * Based upon algorithm properties, and what-not, prioritize a
1208          * proposal, based on the ordering of the ESP algorithms in the
1209          * alternatives in the policy rule or socket that was placed
1210          * in the acquire record.
1211          *
1212          * For each action in policy list
1213          *   Add combination.  If I've hit limit, return.
1214          */
1215 
1216         for (ap = acqrec->ipsacq_act; ap != NULL;
1217             ap = ap->ipa_next) {
1218                 ipsec_alginfo_t *ealg = NULL;


1308         sadb_prop_t *prop;
1309         mblk_t *pfkeymp, *msgmp;
1310         ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
1311         ipsec_stack_t   *ipss = ns->netstack_ipsec;
1312 
1313         ESP_BUMP_STAT(espstack, acquire_requests);
1314 
1315         if (espstack->esp_pfkey_q == NULL) {
1316                 mutex_exit(&acqrec->ipsacq_lock);
1317                 return;
1318         }
1319 
1320         /* Set up ACQUIRE. */
1321         pfkeymp = sadb_setup_acquire(acqrec, SADB_SATYPE_ESP,
1322             ns->netstack_ipsec);
1323         if (pfkeymp == NULL) {
1324                 esp0dbg(("sadb_setup_acquire failed.\n"));
1325                 mutex_exit(&acqrec->ipsacq_lock);
1326                 return;
1327         }
1328         ASSERT(RW_READ_HELD(&ipss->ipsec_alg_lock));
1329         combs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH] *
1330             ipss->ipsec_nalgs[IPSEC_ALG_ENCR];
1331         msgmp = pfkeymp->b_cont;
1332         samsg = (sadb_msg_t *)(msgmp->b_rptr);
1333 
1334         /* Insert proposal here. */
1335 
1336         prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len);
1337         esp_insert_prop(prop, acqrec, combs, ns);
1338         samsg->sadb_msg_len += prop->sadb_prop_len;
1339         msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len);
1340 
1341         rw_exit(&ipss->ipsec_alg_lock);
1342 
1343         /*
1344          * Must mutex_exit() before sending PF_KEY message up, in
1345          * order to avoid recursive mutex_enter() if there are no registered
1346          * listeners.
1347          *
1348          * Once I've sent the message, I'm cool anyway.
1349          */
1350         mutex_exit(&acqrec->ipsacq_lock);
1351         if (extended != NULL) {
1352                 putnext(espstack->esp_pfkey_q, extended);
1353         }
1354         putnext(espstack->esp_pfkey_q, pfkeymp);
1355 }
1356 
1357 /* XXX refactor me */
1358 /*
1359  * Handle the SADB_GETSPI message.  Create a larval SA.
1360  */
1361 static void


3026 
3027         /* Allocate the KEYSOCK_OUT. */
3028         keysock_out_mp = sadb_keysock_out(serial);
3029         if (keysock_out_mp == NULL) {
3030                 esp0dbg(("esp_register_out: couldn't allocate mblk.\n"));
3031                 return (B_FALSE);
3032         }
3033 
3034         if (is_system_labeled() && (cr != NULL)) {
3035                 sens_tsl = crgetlabel(cr);
3036                 if (sens_tsl != NULL) {
3037                         sens_len = sadb_sens_len_from_label(sens_tsl);
3038                         allocsize += sens_len;
3039                 }
3040         }
3041 
3042         /*
3043          * Allocate the PF_KEY message that follows KEYSOCK_OUT.
3044          */
3045 
3046         rw_enter(&ipss->ipsec_alg_lock, RW_READER);
3047         /*
3048          * Fill SADB_REGISTER message's algorithm descriptors.  Hold
3049          * down the lock while filling it.
3050          *
3051          * Return only valid algorithms, so the number of algorithms
3052          * to send up may be less than the number of algorithm entries
3053          * in the table.
3054          */
3055         authalgs = ipss->ipsec_alglists[IPSEC_ALG_AUTH];
3056         for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
3057                 if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
3058                         num_aalgs++;
3059 
3060         if (num_aalgs != 0) {
3061                 allocsize += (num_aalgs * sizeof (*saalg));
3062                 allocsize += sizeof (*sasupp_auth);
3063         }
3064         encralgs = ipss->ipsec_alglists[IPSEC_ALG_ENCR];
3065         for (num_ealgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
3066                 if (encralgs[i] != NULL && ALG_VALID(encralgs[i]))
3067                         num_ealgs++;
3068 
3069         if (num_ealgs != 0) {
3070                 allocsize += (num_ealgs * sizeof (*saalg));
3071                 allocsize += sizeof (*sasupp_encr);
3072         }
3073         keysock_out_mp->b_cont = allocb(allocsize, BPRI_HI);
3074         if (keysock_out_mp->b_cont == NULL) {
3075                 rw_exit(&ipss->ipsec_alg_lock);
3076                 freemsg(keysock_out_mp);
3077                 return (B_FALSE);
3078         }
3079         pfkey_msg_mp = keysock_out_mp->b_cont;
3080         pfkey_msg_mp->b_wptr += allocsize;
3081 
3082         nextext = (sadb_ext_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg));
3083 
3084         if (num_aalgs != 0) {
3085                 sasupp_auth = (sadb_supported_t *)nextext;
3086                 saalg = (sadb_alg_t *)(sasupp_auth + 1);
3087 
3088                 ASSERT(((ulong_t)saalg & 0x7) == 0);
3089 
3090                 numalgs_snap = 0;
3091                 for (i = 0;
3092                     ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs));
3093                     i++) {
3094                         if (authalgs[i] == NULL || !ALG_VALID(authalgs[i]))
3095                                 continue;


3149                 }
3150                 ASSERT(numalgs_snap == num_ealgs);
3151 #ifdef DEBUG
3152                 /*
3153                  * Reality check to make sure I snagged all of the
3154                  * algorithms.
3155                  */
3156                 for (; i < IPSEC_MAX_ALGS; i++) {
3157                         if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) {
3158                                 cmn_err(CE_PANIC, "esp_register_out()! "
3159                                     "Missed ealg #%d.\n", i);
3160                         }
3161                 }
3162 #endif /* DEBUG */
3163                 nextext = (sadb_ext_t *)saalg;
3164         }
3165 
3166         current_aalgs = num_aalgs;
3167         current_ealgs = num_ealgs;
3168 
3169         rw_exit(&ipss->ipsec_alg_lock);
3170 
3171         if (sens_tsl != NULL) {
3172                 sens = (sadb_sens_t *)nextext;
3173                 sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY,
3174                     sens_tsl, sens_len);
3175 
3176                 nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
3177         }
3178 
3179         /* Now fill the rest of the SADB_REGISTER message. */
3180 
3181         samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr;
3182         samsg->sadb_msg_version = PF_KEY_V2;
3183         samsg->sadb_msg_type = SADB_REGISTER;
3184         samsg->sadb_msg_errno = 0;
3185         samsg->sadb_msg_satype = SADB_SATYPE_ESP;
3186         samsg->sadb_msg_len = SADB_8TO64(allocsize);
3187         samsg->sadb_msg_reserved = 0;
3188         /*
3189          * Assume caller has sufficient sequence/pid number info.  If it's one


3674                     !IN6_IS_ADDR_V4MAPPED(&natt_rem6->sin6_addr)) {
3675                         *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM;
3676                         return (EINVAL);
3677                 }
3678         }
3679 
3680 
3681         /* Stuff I don't support, for now.  XXX Diagnostic? */
3682         if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL)
3683                 return (EOPNOTSUPP);
3684 
3685         if ((*diagnostic = sadb_labelchk(ksi)) != 0)
3686                 return (EINVAL);
3687 
3688         /*
3689          * XXX Policy :  I'm not checking identities at this time,
3690          * but if I did, I'd do them here, before I sent
3691          * the weak key check up to the algorithm.
3692          */
3693 
3694         rw_enter(&ipss->ipsec_alg_lock, RW_READER);
3695 
3696         /*
3697          * First locate the authentication algorithm.
3698          */
3699 #ifdef IPSEC_LATENCY_TEST
3700         if (akey != NULL && assoc->sadb_sa_auth != SADB_AALG_NONE) {
3701 #else
3702         if (akey != NULL) {
3703 #endif
3704                 ipsec_alginfo_t *aalg;
3705 
3706                 aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
3707                     [assoc->sadb_sa_auth];
3708                 if (aalg == NULL || !ALG_VALID(aalg)) {
3709                         rw_exit(&ipss->ipsec_alg_lock);
3710                         esp1dbg(espstack, ("Couldn't find auth alg #%d.\n",
3711                             assoc->sadb_sa_auth));
3712                         *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
3713                         return (EINVAL);
3714                 }
3715 
3716                 /*
3717                  * Sanity check key sizes.
3718                  * Note: It's not possible to use SADB_AALG_NONE because
3719                  * this auth_alg is not defined with ALG_FLAG_VALID. If this
3720                  * ever changes, the same check for SADB_AALG_NONE and
3721                  * a auth_key != NULL should be made here ( see below).
3722                  */
3723                 if (!ipsec_valid_key_size(akey->sadb_key_bits, aalg)) {
3724                         rw_exit(&ipss->ipsec_alg_lock);
3725                         *diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS;
3726                         return (EINVAL);
3727                 }
3728                 ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
3729 
3730                 /* check key and fix parity if needed */
3731                 if (ipsec_check_key(aalg->alg_mech_type, akey, B_TRUE,
3732                     diagnostic) != 0) {
3733                         rw_exit(&ipss->ipsec_alg_lock);
3734                         return (EINVAL);
3735                 }
3736         }
3737 
3738         /*
3739          * Then locate the encryption algorithm.
3740          */
3741         if (ekey != NULL) {
3742                 uint_t keybits;
3743                 ipsec_alginfo_t *ealg;
3744 
3745                 ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR]
3746                     [assoc->sadb_sa_encrypt];
3747                 if (ealg == NULL || !ALG_VALID(ealg)) {
3748                         rw_exit(&ipss->ipsec_alg_lock);
3749                         esp1dbg(espstack, ("Couldn't find encr alg #%d.\n",
3750                             assoc->sadb_sa_encrypt));
3751                         *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG;
3752                         return (EINVAL);
3753                 }
3754 
3755                 /*
3756                  * Sanity check key sizes. If the encryption algorithm is
3757                  * SADB_EALG_NULL but the encryption key is NOT
3758                  * NULL then complain.
3759                  *
3760                  * The keying material includes salt bits if required by
3761                  * algorithm and optionally the Initial IV, check the
3762                  * length of whats left.
3763                  */
3764                 keybits = ekey->sadb_key_bits;
3765                 keybits -= ekey->sadb_key_reserved;
3766                 keybits -= SADB_8TO1(ealg->alg_saltlen);
3767                 if ((assoc->sadb_sa_encrypt == SADB_EALG_NULL) ||
3768                     (!ipsec_valid_key_size(keybits, ealg))) {
3769                         rw_exit(&ipss->ipsec_alg_lock);
3770                         *diagnostic = SADB_X_DIAGNOSTIC_BAD_EKEYBITS;
3771                         return (EINVAL);
3772                 }
3773                 ASSERT(ealg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
3774 
3775                 /* check key */
3776                 if (ipsec_check_key(ealg->alg_mech_type, ekey, B_FALSE,
3777                     diagnostic) != 0) {
3778                         rw_exit(&ipss->ipsec_alg_lock);
3779                         return (EINVAL);
3780                 }
3781         }
3782         rw_exit(&ipss->ipsec_alg_lock);
3783 
3784         return (esp_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi,
3785             diagnostic, espstack));
3786 }
3787 
3788 /*
3789  * Update a security association.  Updates come in two varieties.  The first
3790  * is an update of lifetimes on a non-larval SA.  The second is an update of
3791  * a larval SA, which ends up looking a lot more like an add.
3792  */
3793 static int
3794 esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
3795     ipsecesp_stack_t *espstack, uint8_t sadb_msg_type)
3796 {
3797         sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
3798         mblk_t    *buf_pkt;
3799         int rcode;
3800 
3801         sadb_address_t *dstext =
3802             (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];