Print this page
4788 mac shouldn't abuse ddi_get_time(9f)


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  */



  25 
  26 #include <sys/strsun.h>
  27 #include <sys/sdt.h>
  28 #include <sys/mac.h>
  29 #include <sys/mac_impl.h>
  30 #include <sys/mac_client_impl.h>
  31 #include <sys/mac_client_priv.h>
  32 #include <sys/ethernet.h>
  33 #include <sys/vlan.h>
  34 #include <sys/dlpi.h>
  35 #include <sys/avl.h>
  36 #include <inet/ip.h>
  37 #include <inet/ip6.h>
  38 #include <inet/arp.h>
  39 #include <netinet/arp.h>
  40 #include <netinet/udp.h>
  41 #include <netinet/dhcp.h>
  42 #include <netinet/dhcp6.h>
  43 
  44 /*


 124  *    Packets with a source address matching one of the DHCPv6-assigned
 125  *    addresses will be allowed through.
 126  *
 127  * IPv6 notes:
 128  *
 129  * The v6 code shares the same timer as v4 for scrubbing stale transactions.
 130  * Just like v4, as part of removing an expired transaction, a RELEASE will be
 131  * be triggered on the cid associated with the expired transaction.
 132  *
 133  * The data structures used for v6 are slightly different because a v6 client
 134  * may have multiple addresses associated with it.
 135  */
 136 
 137 /*
 138  * These are just arbitrary limits meant for preventing abuse (e.g. a user
 139  * flooding the network with bogus transactions). They are not meant to be
 140  * user-modifiable so they are not exposed as linkprops.
 141  */
 142 static ulong_t  dhcp_max_pending_txn = 512;
 143 static ulong_t  dhcp_max_completed_txn = 512;
 144 static time_t   txn_cleanup_interval = 60;
 145 
 146 /*
 147  * DHCPv4 transaction. It may be added to three different tables
 148  * (keyed by different fields).
 149  */
 150 typedef struct dhcpv4_txn {
 151         uint32_t                dt_xid;
 152         time_t                  dt_timestamp;
 153         uint8_t                 dt_cid[DHCP_MAX_OPT_SIZE];
 154         uint8_t                 dt_cid_len;
 155         ipaddr_t                dt_ipaddr;
 156         avl_node_t              dt_node;
 157         avl_node_t              dt_ipnode;
 158         struct dhcpv4_txn       *dt_next;
 159 } dhcpv4_txn_t;
 160 
 161 /*
 162  * DHCPv6 address. May be added to mci_v6_dyn_ip.
 163  * It is always pointed to by its parent dhcpv6_cid_t structure.
 164  */
 165 typedef struct dhcpv6_addr {
 166         in6_addr_t              da_addr;
 167         avl_node_t              da_node;
 168         struct dhcpv6_addr      *da_next;
 169 } dhcpv6_addr_t;
 170 
 171 /*
 172  * DHCPv6 client ID. May be added to mci_v6_cid.
 173  * No dhcpv6_txn_t should be pointing to it after it is added to mci_v6_cid.
 174  */
 175 typedef struct dhcpv6_cid {
 176         uchar_t                 *dc_cid;
 177         uint_t                  dc_cid_len;
 178         dhcpv6_addr_t           *dc_addr;
 179         uint_t                  dc_addrcnt;
 180         avl_node_t              dc_node;
 181 } dhcpv6_cid_t;
 182 
 183 /*
 184  * DHCPv6 transaction. Unlike its v4 counterpart, this object gets freed up
 185  * as soon as the transaction completes or expires.
 186  */
 187 typedef struct dhcpv6_txn {
 188         uint32_t                dt_xid;
 189         time_t                  dt_timestamp;
 190         dhcpv6_cid_t            *dt_cid;
 191         avl_node_t              dt_node;
 192         struct dhcpv6_txn       *dt_next;
 193 } dhcpv6_txn_t;
 194 
 195 static void     start_txn_cleanup_timer(mac_client_impl_t *);
 196 static boolean_t allowed_ips_set(mac_resource_props_t *, uint32_t);
 197 
 198 #define BUMP_STAT(m, s) (m)->mci_misc_stat.mms_##s++
 199 
 200 /*
 201  * Comparison functions for the 3 AVL trees used:
 202  * mci_v4_pending_txn, mci_v4_completed_txn, mci_v4_dyn_ip
 203  */
 204 static int
 205 compare_dhcpv4_xid(const void *arg1, const void *arg2)
 206 {
 207         const dhcpv4_txn_t      *txn1 = arg1, *txn2 = arg2;
 208 
 209         if (txn1->dt_xid < txn2->dt_xid)


 438 
 439         mutex_enter(&mcip->mci_protect_lock);
 440         tmp_txn.dt_ipaddr = ipaddr;
 441         txn = avl_find(&mcip->mci_v4_dyn_ip, &tmp_txn, NULL);
 442         mutex_exit(&mcip->mci_protect_lock);
 443         return (txn != NULL);
 444 }
 445 
 446 /*
 447  * Create/destroy a DHCPv4 transaction.
 448  */
 449 static dhcpv4_txn_t *
 450 create_dhcpv4_txn(uint32_t xid, uint8_t *cid, uint8_t cid_len, ipaddr_t ipaddr)
 451 {
 452         dhcpv4_txn_t    *txn;
 453 
 454         if ((txn = kmem_zalloc(sizeof (*txn), KM_NOSLEEP)) == NULL)
 455                 return (NULL);
 456 
 457         txn->dt_xid = xid;
 458         txn->dt_timestamp = ddi_get_time();
 459         if (cid_len > 0)
 460                 bcopy(cid, &txn->dt_cid, cid_len);
 461         txn->dt_cid_len = cid_len;
 462         txn->dt_ipaddr = ipaddr;
 463         return (txn);
 464 }
 465 
 466 static void
 467 free_dhcpv4_txn(dhcpv4_txn_t *txn)
 468 {
 469         kmem_free(txn, sizeof (*txn));
 470 }
 471 
 472 /*
 473  * Clean up all v4 tables.
 474  */
 475 static void
 476 flush_dhcpv4(mac_client_impl_t *mcip)
 477 {
 478         void            *cookie = NULL;


 495         while ((txn = avl_destroy_nodes(&mcip->mci_v4_pending_txn,
 496             &cookie)) != NULL) {
 497                 free_dhcpv4_txn(txn);
 498         }
 499 }
 500 
 501 /*
 502  * Cleanup stale DHCPv4 transactions.
 503  */
 504 static void
 505 txn_cleanup_v4(mac_client_impl_t *mcip)
 506 {
 507         dhcpv4_txn_t            *txn, *ctxn, *next, *txn_list = NULL;
 508 
 509         /*
 510          * Find stale pending transactions and place them on a list
 511          * to be removed.
 512          */
 513         for (txn = avl_first(&mcip->mci_v4_pending_txn); txn != NULL;
 514             txn = avl_walk(&mcip->mci_v4_pending_txn, txn, AVL_AFTER)) {
 515                 if (ddi_get_time() - txn->dt_timestamp >
 516                     txn_cleanup_interval) {
 517                         DTRACE_PROBE2(found__expired__txn,
 518                             mac_client_impl_t *, mcip,
 519                             dhcpv4_txn_t *, txn);
 520 
 521                         txn->dt_next = txn_list;
 522                         txn_list = txn;
 523                 }
 524         }
 525 
 526         /*
 527          * Remove and free stale pending transactions and completed
 528          * transactions with the same client IDs as the stale transactions.
 529          */
 530         for (txn = txn_list; txn != NULL; txn = next) {
 531                 avl_remove(&mcip->mci_v4_pending_txn, txn);
 532 
 533                 ctxn = find_dhcpv4_completed_txn(mcip, txn->dt_cid,
 534                     txn->dt_cid_len);
 535                 if (ctxn != NULL) {
 536                         DTRACE_PROBE2(removing__completed__txn,


 600                 /* flush any completed txn with this cid */
 601                 ctxn = find_dhcpv4_completed_txn(mcip, cid, cid_len);
 602                 if (ctxn != NULL) {
 603                         DTRACE_PROBE2(release__successful, mac_client_impl_t *,
 604                             mcip, struct dhcp *, dh4);
 605 
 606                         remove_dhcpv4_completed_txn(mcip, ctxn);
 607                         free_dhcpv4_txn(ctxn);
 608                 }
 609                 goto done;
 610         }
 611 
 612         /*
 613          * If a pending txn already exists, we'll update its timestamp so
 614          * it won't get flushed by the timer. We don't need to create new
 615          * txns for retransmissions.
 616          */
 617         if ((txn = find_dhcpv4_pending_txn(mcip, dh4->xid)) != NULL) {
 618                 DTRACE_PROBE2(update, mac_client_impl_t *, mcip,
 619                     dhcpv4_txn_t *, txn);
 620                 txn->dt_timestamp = ddi_get_time();
 621                 goto done;
 622         }
 623 
 624         if (get_dhcpv4_option(dh4, end, CD_REQUESTED_IP_ADDR,
 625             &opt, &opt_len) != 0 || opt_len != sizeof (ipaddr)) {
 626                 DTRACE_PROBE2(ipaddr__not__found, mac_client_impl_t *, mcip,
 627                     struct dhcp *, dh4);
 628                 goto done;
 629         }
 630         bcopy(opt, &ipaddr, sizeof (ipaddr));
 631         if ((txn = create_dhcpv4_txn(dh4->xid, cid, cid_len, ipaddr)) == NULL)
 632                 goto done;
 633 
 634         if (insert_dhcpv4_pending_txn(mcip, txn) != 0) {
 635                 DTRACE_PROBE2(insert__failed, mac_client_impl_t *, mcip,
 636                     dhcpv4_txn_t *, txn);
 637                 free_dhcpv4_txn(txn);
 638                 goto done;
 639         }
 640         start_txn_cleanup_timer(mcip);


1099         return (avl_find(&mcip->mci_v6_pending_txn, &tmp_txn, NULL));
1100 }
1101 
1102 static void
1103 remove_dhcpv6_pending_txn(mac_client_impl_t *mcip, dhcpv6_txn_t *txn)
1104 {
1105         ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
1106         avl_remove(&mcip->mci_v6_pending_txn, txn);
1107 }
1108 
1109 static dhcpv6_txn_t *
1110 create_dhcpv6_txn(uint32_t xid, dhcpv6_cid_t *cid)
1111 {
1112         dhcpv6_txn_t    *txn;
1113 
1114         if ((txn = kmem_zalloc(sizeof (dhcpv6_txn_t), KM_NOSLEEP)) == NULL)
1115                 return (NULL);
1116 
1117         txn->dt_xid = xid;
1118         txn->dt_cid = cid;
1119         txn->dt_timestamp = ddi_get_time();
1120         return (txn);
1121 }
1122 
1123 static void
1124 free_dhcpv6_txn(dhcpv6_txn_t *txn)
1125 {
1126         if (txn->dt_cid != NULL)
1127                 free_dhcpv6_cid(txn->dt_cid);
1128         kmem_free(txn, sizeof (dhcpv6_txn_t));
1129 }
1130 
1131 static int
1132 insert_dhcpv6_pending_txn(mac_client_impl_t *mcip, dhcpv6_txn_t *txn)
1133 {
1134         avl_index_t     where;
1135 
1136         ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
1137         if (avl_find(&mcip->mci_v6_pending_txn, txn, &where) != NULL)
1138                 return (EEXIST);
1139 


1166         while ((txn = avl_destroy_nodes(&mcip->mci_v6_pending_txn,
1167             &cookie)) != NULL) {
1168                 free_dhcpv6_txn(txn);
1169         }
1170 }
1171 
1172 /*
1173  * Cleanup stale DHCPv6 transactions.
1174  */
1175 static void
1176 txn_cleanup_v6(mac_client_impl_t *mcip)
1177 {
1178         dhcpv6_txn_t            *txn, *next, *txn_list = NULL;
1179 
1180         /*
1181          * Find stale pending transactions and place them on a list
1182          * to be removed.
1183          */
1184         for (txn = avl_first(&mcip->mci_v6_pending_txn); txn != NULL;
1185             txn = avl_walk(&mcip->mci_v6_pending_txn, txn, AVL_AFTER)) {
1186                 if (ddi_get_time() - txn->dt_timestamp >
1187                     txn_cleanup_interval) {
1188                         DTRACE_PROBE2(found__expired__txn,
1189                             mac_client_impl_t *, mcip,
1190                             dhcpv6_txn_t *, txn);
1191 
1192                         txn->dt_next = txn_list;
1193                         txn_list = txn;
1194                 }
1195         }
1196 
1197         /*
1198          * Remove and free stale pending transactions.
1199          * Release any existing cids matching the stale transactions.
1200          */
1201         for (txn = txn_list; txn != NULL; txn = next) {
1202                 avl_remove(&mcip->mci_v6_pending_txn, txn);
1203                 release_dhcpv6_cid(mcip, txn->dt_cid);
1204                 next = txn->dt_next;
1205                 txn->dt_next = NULL;
1206 
1207                 DTRACE_PROBE2(freeing__txn, mac_client_impl_t *, mcip,


1231         if (allowed_ips_set(mrp, IPV6_VERSION))
1232                 return (B_FALSE);
1233 
1234         mtype = dh6->d6m_msg_type;
1235         if (mtype != DHCPV6_MSG_REQUEST && mtype != DHCPV6_MSG_RENEW &&
1236             mtype != DHCPV6_MSG_REBIND && mtype != DHCPV6_MSG_RELEASE)
1237                 return (B_TRUE);
1238 
1239         if ((cid = create_dhcpv6_cid(dh6, end)) == NULL)
1240                 return (B_TRUE);
1241 
1242         mutex_enter(&mcip->mci_protect_lock);
1243         if (mtype == DHCPV6_MSG_RELEASE) {
1244                 release_dhcpv6_cid(mcip, cid);
1245                 goto done;
1246         }
1247         xid = DHCPV6_GET_TRANSID(dh6);
1248         if ((txn = find_dhcpv6_pending_txn(mcip, xid)) != NULL) {
1249                 DTRACE_PROBE2(update, mac_client_impl_t *, mcip,
1250                     dhcpv6_txn_t *, txn);
1251                 txn->dt_timestamp = ddi_get_time();
1252                 goto done;
1253         }
1254         if ((txn = create_dhcpv6_txn(xid, cid)) == NULL)
1255                 goto done;
1256 
1257         cid = NULL;
1258         if (insert_dhcpv6_pending_txn(mcip, txn) != 0) {
1259                 DTRACE_PROBE2(insert__failed, mac_client_impl_t *, mcip,
1260                     dhcpv6_txn_t *, txn);
1261                 free_dhcpv6_txn(txn);
1262                 goto done;
1263         }
1264         start_txn_cleanup_timer(mcip);
1265 
1266         DTRACE_PROBE2(txn__pending, mac_client_impl_t *, mcip,
1267             dhcpv6_txn_t *, txn);
1268 
1269 done:
1270         if (cid != NULL)
1271                 free_dhcpv6_cid(cid);


1340 
1341         mutex_enter(&mcip->mci_protect_lock);
1342         if (mcip->mci_txn_cleanup_tid == 0) {
1343                 /* do nothing if timer got cancelled */
1344                 mutex_exit(&mcip->mci_protect_lock);
1345                 return;
1346         }
1347         mcip->mci_txn_cleanup_tid = 0;
1348 
1349         txn_cleanup_v4(mcip);
1350         txn_cleanup_v6(mcip);
1351 
1352         /*
1353          * Restart timer if pending transactions still exist.
1354          */
1355         if (!avl_is_empty(&mcip->mci_v4_pending_txn) ||
1356             !avl_is_empty(&mcip->mci_v6_pending_txn)) {
1357                 DTRACE_PROBE1(restarting__timer, mac_client_impl_t *, mcip);
1358 
1359                 mcip->mci_txn_cleanup_tid = timeout(txn_cleanup_timer, mcip,
1360                     drv_usectohz(txn_cleanup_interval * 1000000));
1361         }
1362         mutex_exit(&mcip->mci_protect_lock);
1363 }
1364 
1365 static void
1366 start_txn_cleanup_timer(mac_client_impl_t *mcip)
1367 {
1368         ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
1369         if (mcip->mci_txn_cleanup_tid == 0) {
1370                 mcip->mci_txn_cleanup_tid = timeout(txn_cleanup_timer, mcip,
1371                     drv_usectohz(txn_cleanup_interval * 1000000));
1372         }
1373 }
1374 
1375 static void
1376 cancel_txn_cleanup_timer(mac_client_impl_t *mcip)
1377 {
1378         timeout_id_t    tid;
1379 
1380         ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
1381 
1382         /*
1383          * This needs to be a while loop because the timer could get
1384          * rearmed during untimeout().
1385          */
1386         while ((tid = mcip->mci_txn_cleanup_tid) != 0) {
1387                 mcip->mci_txn_cleanup_tid = 0;
1388                 mutex_exit(&mcip->mci_protect_lock);
1389                 (void) untimeout(tid);
1390                 mutex_enter(&mcip->mci_protect_lock);
1391         }




   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 /*
  26  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  27  */
  28 
  29 #include <sys/strsun.h>
  30 #include <sys/sdt.h>
  31 #include <sys/mac.h>
  32 #include <sys/mac_impl.h>
  33 #include <sys/mac_client_impl.h>
  34 #include <sys/mac_client_priv.h>
  35 #include <sys/ethernet.h>
  36 #include <sys/vlan.h>
  37 #include <sys/dlpi.h>
  38 #include <sys/avl.h>
  39 #include <inet/ip.h>
  40 #include <inet/ip6.h>
  41 #include <inet/arp.h>
  42 #include <netinet/arp.h>
  43 #include <netinet/udp.h>
  44 #include <netinet/dhcp.h>
  45 #include <netinet/dhcp6.h>
  46 
  47 /*


 127  *    Packets with a source address matching one of the DHCPv6-assigned
 128  *    addresses will be allowed through.
 129  *
 130  * IPv6 notes:
 131  *
 132  * The v6 code shares the same timer as v4 for scrubbing stale transactions.
 133  * Just like v4, as part of removing an expired transaction, a RELEASE will be
 134  * be triggered on the cid associated with the expired transaction.
 135  *
 136  * The data structures used for v6 are slightly different because a v6 client
 137  * may have multiple addresses associated with it.
 138  */
 139 
 140 /*
 141  * These are just arbitrary limits meant for preventing abuse (e.g. a user
 142  * flooding the network with bogus transactions). They are not meant to be
 143  * user-modifiable so they are not exposed as linkprops.
 144  */
 145 static ulong_t  dhcp_max_pending_txn = 512;
 146 static ulong_t  dhcp_max_completed_txn = 512;
 147 static hrtime_t txn_cleanup_interval = 60 * NANOSEC;
 148 
 149 /*
 150  * DHCPv4 transaction. It may be added to three different tables
 151  * (keyed by different fields).
 152  */
 153 typedef struct dhcpv4_txn {
 154         uint32_t                dt_xid;
 155         hrtime_t                dt_timestamp;
 156         uint8_t                 dt_cid[DHCP_MAX_OPT_SIZE];
 157         uint8_t                 dt_cid_len;
 158         ipaddr_t                dt_ipaddr;
 159         avl_node_t              dt_node;
 160         avl_node_t              dt_ipnode;
 161         struct dhcpv4_txn       *dt_next;
 162 } dhcpv4_txn_t;
 163 
 164 /*
 165  * DHCPv6 address. May be added to mci_v6_dyn_ip.
 166  * It is always pointed to by its parent dhcpv6_cid_t structure.
 167  */
 168 typedef struct dhcpv6_addr {
 169         in6_addr_t              da_addr;
 170         avl_node_t              da_node;
 171         struct dhcpv6_addr      *da_next;
 172 } dhcpv6_addr_t;
 173 
 174 /*
 175  * DHCPv6 client ID. May be added to mci_v6_cid.
 176  * No dhcpv6_txn_t should be pointing to it after it is added to mci_v6_cid.
 177  */
 178 typedef struct dhcpv6_cid {
 179         uchar_t                 *dc_cid;
 180         uint_t                  dc_cid_len;
 181         dhcpv6_addr_t           *dc_addr;
 182         uint_t                  dc_addrcnt;
 183         avl_node_t              dc_node;
 184 } dhcpv6_cid_t;
 185 
 186 /*
 187  * DHCPv6 transaction. Unlike its v4 counterpart, this object gets freed up
 188  * as soon as the transaction completes or expires.
 189  */
 190 typedef struct dhcpv6_txn {
 191         uint32_t                dt_xid;
 192         hrtime_t                dt_timestamp;
 193         dhcpv6_cid_t            *dt_cid;
 194         avl_node_t              dt_node;
 195         struct dhcpv6_txn       *dt_next;
 196 } dhcpv6_txn_t;
 197 
 198 static void     start_txn_cleanup_timer(mac_client_impl_t *);
 199 static boolean_t allowed_ips_set(mac_resource_props_t *, uint32_t);
 200 
 201 #define BUMP_STAT(m, s) (m)->mci_misc_stat.mms_##s++
 202 
 203 /*
 204  * Comparison functions for the 3 AVL trees used:
 205  * mci_v4_pending_txn, mci_v4_completed_txn, mci_v4_dyn_ip
 206  */
 207 static int
 208 compare_dhcpv4_xid(const void *arg1, const void *arg2)
 209 {
 210         const dhcpv4_txn_t      *txn1 = arg1, *txn2 = arg2;
 211 
 212         if (txn1->dt_xid < txn2->dt_xid)


 441 
 442         mutex_enter(&mcip->mci_protect_lock);
 443         tmp_txn.dt_ipaddr = ipaddr;
 444         txn = avl_find(&mcip->mci_v4_dyn_ip, &tmp_txn, NULL);
 445         mutex_exit(&mcip->mci_protect_lock);
 446         return (txn != NULL);
 447 }
 448 
 449 /*
 450  * Create/destroy a DHCPv4 transaction.
 451  */
 452 static dhcpv4_txn_t *
 453 create_dhcpv4_txn(uint32_t xid, uint8_t *cid, uint8_t cid_len, ipaddr_t ipaddr)
 454 {
 455         dhcpv4_txn_t    *txn;
 456 
 457         if ((txn = kmem_zalloc(sizeof (*txn), KM_NOSLEEP)) == NULL)
 458                 return (NULL);
 459 
 460         txn->dt_xid = xid;
 461         txn->dt_timestamp = gethrtime();
 462         if (cid_len > 0)
 463                 bcopy(cid, &txn->dt_cid, cid_len);
 464         txn->dt_cid_len = cid_len;
 465         txn->dt_ipaddr = ipaddr;
 466         return (txn);
 467 }
 468 
 469 static void
 470 free_dhcpv4_txn(dhcpv4_txn_t *txn)
 471 {
 472         kmem_free(txn, sizeof (*txn));
 473 }
 474 
 475 /*
 476  * Clean up all v4 tables.
 477  */
 478 static void
 479 flush_dhcpv4(mac_client_impl_t *mcip)
 480 {
 481         void            *cookie = NULL;


 498         while ((txn = avl_destroy_nodes(&mcip->mci_v4_pending_txn,
 499             &cookie)) != NULL) {
 500                 free_dhcpv4_txn(txn);
 501         }
 502 }
 503 
 504 /*
 505  * Cleanup stale DHCPv4 transactions.
 506  */
 507 static void
 508 txn_cleanup_v4(mac_client_impl_t *mcip)
 509 {
 510         dhcpv4_txn_t            *txn, *ctxn, *next, *txn_list = NULL;
 511 
 512         /*
 513          * Find stale pending transactions and place them on a list
 514          * to be removed.
 515          */
 516         for (txn = avl_first(&mcip->mci_v4_pending_txn); txn != NULL;
 517             txn = avl_walk(&mcip->mci_v4_pending_txn, txn, AVL_AFTER)) {
 518                 if (gethrtime() - txn->dt_timestamp > txn_cleanup_interval) {

 519                         DTRACE_PROBE2(found__expired__txn,
 520                             mac_client_impl_t *, mcip,
 521                             dhcpv4_txn_t *, txn);
 522 
 523                         txn->dt_next = txn_list;
 524                         txn_list = txn;
 525                 }
 526         }
 527 
 528         /*
 529          * Remove and free stale pending transactions and completed
 530          * transactions with the same client IDs as the stale transactions.
 531          */
 532         for (txn = txn_list; txn != NULL; txn = next) {
 533                 avl_remove(&mcip->mci_v4_pending_txn, txn);
 534 
 535                 ctxn = find_dhcpv4_completed_txn(mcip, txn->dt_cid,
 536                     txn->dt_cid_len);
 537                 if (ctxn != NULL) {
 538                         DTRACE_PROBE2(removing__completed__txn,


 602                 /* flush any completed txn with this cid */
 603                 ctxn = find_dhcpv4_completed_txn(mcip, cid, cid_len);
 604                 if (ctxn != NULL) {
 605                         DTRACE_PROBE2(release__successful, mac_client_impl_t *,
 606                             mcip, struct dhcp *, dh4);
 607 
 608                         remove_dhcpv4_completed_txn(mcip, ctxn);
 609                         free_dhcpv4_txn(ctxn);
 610                 }
 611                 goto done;
 612         }
 613 
 614         /*
 615          * If a pending txn already exists, we'll update its timestamp so
 616          * it won't get flushed by the timer. We don't need to create new
 617          * txns for retransmissions.
 618          */
 619         if ((txn = find_dhcpv4_pending_txn(mcip, dh4->xid)) != NULL) {
 620                 DTRACE_PROBE2(update, mac_client_impl_t *, mcip,
 621                     dhcpv4_txn_t *, txn);
 622                 txn->dt_timestamp = gethrtime();
 623                 goto done;
 624         }
 625 
 626         if (get_dhcpv4_option(dh4, end, CD_REQUESTED_IP_ADDR,
 627             &opt, &opt_len) != 0 || opt_len != sizeof (ipaddr)) {
 628                 DTRACE_PROBE2(ipaddr__not__found, mac_client_impl_t *, mcip,
 629                     struct dhcp *, dh4);
 630                 goto done;
 631         }
 632         bcopy(opt, &ipaddr, sizeof (ipaddr));
 633         if ((txn = create_dhcpv4_txn(dh4->xid, cid, cid_len, ipaddr)) == NULL)
 634                 goto done;
 635 
 636         if (insert_dhcpv4_pending_txn(mcip, txn) != 0) {
 637                 DTRACE_PROBE2(insert__failed, mac_client_impl_t *, mcip,
 638                     dhcpv4_txn_t *, txn);
 639                 free_dhcpv4_txn(txn);
 640                 goto done;
 641         }
 642         start_txn_cleanup_timer(mcip);


1101         return (avl_find(&mcip->mci_v6_pending_txn, &tmp_txn, NULL));
1102 }
1103 
1104 static void
1105 remove_dhcpv6_pending_txn(mac_client_impl_t *mcip, dhcpv6_txn_t *txn)
1106 {
1107         ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
1108         avl_remove(&mcip->mci_v6_pending_txn, txn);
1109 }
1110 
1111 static dhcpv6_txn_t *
1112 create_dhcpv6_txn(uint32_t xid, dhcpv6_cid_t *cid)
1113 {
1114         dhcpv6_txn_t    *txn;
1115 
1116         if ((txn = kmem_zalloc(sizeof (dhcpv6_txn_t), KM_NOSLEEP)) == NULL)
1117                 return (NULL);
1118 
1119         txn->dt_xid = xid;
1120         txn->dt_cid = cid;
1121         txn->dt_timestamp = gethrtime();
1122         return (txn);
1123 }
1124 
1125 static void
1126 free_dhcpv6_txn(dhcpv6_txn_t *txn)
1127 {
1128         if (txn->dt_cid != NULL)
1129                 free_dhcpv6_cid(txn->dt_cid);
1130         kmem_free(txn, sizeof (dhcpv6_txn_t));
1131 }
1132 
1133 static int
1134 insert_dhcpv6_pending_txn(mac_client_impl_t *mcip, dhcpv6_txn_t *txn)
1135 {
1136         avl_index_t     where;
1137 
1138         ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
1139         if (avl_find(&mcip->mci_v6_pending_txn, txn, &where) != NULL)
1140                 return (EEXIST);
1141 


1168         while ((txn = avl_destroy_nodes(&mcip->mci_v6_pending_txn,
1169             &cookie)) != NULL) {
1170                 free_dhcpv6_txn(txn);
1171         }
1172 }
1173 
1174 /*
1175  * Cleanup stale DHCPv6 transactions.
1176  */
1177 static void
1178 txn_cleanup_v6(mac_client_impl_t *mcip)
1179 {
1180         dhcpv6_txn_t            *txn, *next, *txn_list = NULL;
1181 
1182         /*
1183          * Find stale pending transactions and place them on a list
1184          * to be removed.
1185          */
1186         for (txn = avl_first(&mcip->mci_v6_pending_txn); txn != NULL;
1187             txn = avl_walk(&mcip->mci_v6_pending_txn, txn, AVL_AFTER)) {
1188                 if (gethrtime() - txn->dt_timestamp > txn_cleanup_interval) {

1189                         DTRACE_PROBE2(found__expired__txn,
1190                             mac_client_impl_t *, mcip,
1191                             dhcpv6_txn_t *, txn);
1192 
1193                         txn->dt_next = txn_list;
1194                         txn_list = txn;
1195                 }
1196         }
1197 
1198         /*
1199          * Remove and free stale pending transactions.
1200          * Release any existing cids matching the stale transactions.
1201          */
1202         for (txn = txn_list; txn != NULL; txn = next) {
1203                 avl_remove(&mcip->mci_v6_pending_txn, txn);
1204                 release_dhcpv6_cid(mcip, txn->dt_cid);
1205                 next = txn->dt_next;
1206                 txn->dt_next = NULL;
1207 
1208                 DTRACE_PROBE2(freeing__txn, mac_client_impl_t *, mcip,


1232         if (allowed_ips_set(mrp, IPV6_VERSION))
1233                 return (B_FALSE);
1234 
1235         mtype = dh6->d6m_msg_type;
1236         if (mtype != DHCPV6_MSG_REQUEST && mtype != DHCPV6_MSG_RENEW &&
1237             mtype != DHCPV6_MSG_REBIND && mtype != DHCPV6_MSG_RELEASE)
1238                 return (B_TRUE);
1239 
1240         if ((cid = create_dhcpv6_cid(dh6, end)) == NULL)
1241                 return (B_TRUE);
1242 
1243         mutex_enter(&mcip->mci_protect_lock);
1244         if (mtype == DHCPV6_MSG_RELEASE) {
1245                 release_dhcpv6_cid(mcip, cid);
1246                 goto done;
1247         }
1248         xid = DHCPV6_GET_TRANSID(dh6);
1249         if ((txn = find_dhcpv6_pending_txn(mcip, xid)) != NULL) {
1250                 DTRACE_PROBE2(update, mac_client_impl_t *, mcip,
1251                     dhcpv6_txn_t *, txn);
1252                 txn->dt_timestamp = gethrtime();
1253                 goto done;
1254         }
1255         if ((txn = create_dhcpv6_txn(xid, cid)) == NULL)
1256                 goto done;
1257 
1258         cid = NULL;
1259         if (insert_dhcpv6_pending_txn(mcip, txn) != 0) {
1260                 DTRACE_PROBE2(insert__failed, mac_client_impl_t *, mcip,
1261                     dhcpv6_txn_t *, txn);
1262                 free_dhcpv6_txn(txn);
1263                 goto done;
1264         }
1265         start_txn_cleanup_timer(mcip);
1266 
1267         DTRACE_PROBE2(txn__pending, mac_client_impl_t *, mcip,
1268             dhcpv6_txn_t *, txn);
1269 
1270 done:
1271         if (cid != NULL)
1272                 free_dhcpv6_cid(cid);


1341 
1342         mutex_enter(&mcip->mci_protect_lock);
1343         if (mcip->mci_txn_cleanup_tid == 0) {
1344                 /* do nothing if timer got cancelled */
1345                 mutex_exit(&mcip->mci_protect_lock);
1346                 return;
1347         }
1348         mcip->mci_txn_cleanup_tid = 0;
1349 
1350         txn_cleanup_v4(mcip);
1351         txn_cleanup_v6(mcip);
1352 
1353         /*
1354          * Restart timer if pending transactions still exist.
1355          */
1356         if (!avl_is_empty(&mcip->mci_v4_pending_txn) ||
1357             !avl_is_empty(&mcip->mci_v6_pending_txn)) {
1358                 DTRACE_PROBE1(restarting__timer, mac_client_impl_t *, mcip);
1359 
1360                 mcip->mci_txn_cleanup_tid = timeout(txn_cleanup_timer, mcip,
1361                     drv_usectohz(txn_cleanup_interval / (NANOSEC / MICROSEC)));
1362         }
1363         mutex_exit(&mcip->mci_protect_lock);
1364 }
1365 
1366 static void
1367 start_txn_cleanup_timer(mac_client_impl_t *mcip)
1368 {
1369         ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
1370         if (mcip->mci_txn_cleanup_tid == 0) {
1371                 mcip->mci_txn_cleanup_tid = timeout(txn_cleanup_timer, mcip,
1372                     drv_usectohz(txn_cleanup_interval / (NANOSEC / MICROSEC)));
1373         }
1374 }
1375 
1376 static void
1377 cancel_txn_cleanup_timer(mac_client_impl_t *mcip)
1378 {
1379         timeout_id_t    tid;
1380 
1381         ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
1382 
1383         /*
1384          * This needs to be a while loop because the timer could get
1385          * rearmed during untimeout().
1386          */
1387         while ((tid = mcip->mci_txn_cleanup_tid) != 0) {
1388                 mcip->mci_txn_cleanup_tid = 0;
1389                 mutex_exit(&mcip->mci_protect_lock);
1390                 (void) untimeout(tid);
1391                 mutex_enter(&mcip->mci_protect_lock);
1392         }