+ if (vlp->vlp_signature != VLP_SIGNATURE) {
+ panic("vlan_parent_retain: signature is bad\n");
+ }
+ if (vlp->vlp_retain_count == 0) {
+ panic("vlan_parent_retain: retain count is 0\n");
+ }
+ OSIncrementAtomic(&vlp->vlp_retain_count);
+}
+
+static void
+vlan_parent_release(vlan_parent_ref vlp)
+{
+ u_int32_t old_retain_count;
+
+ if (vlp->vlp_signature != VLP_SIGNATURE) {
+ panic("vlan_parent_release: signature is bad\n");
+ }
+ old_retain_count = OSDecrementAtomic(&vlp->vlp_retain_count);
+ switch (old_retain_count) {
+ case 0:
+ panic("vlan_parent_release: retain count is 0\n");
+ break;
+ case 1:
+ if (g_vlan->verbose) {
+ struct ifnet * ifp = vlp->vlp_ifp;
+ printf("vlan_parent_release(%s%d)\n", ifnet_name(ifp),
+ ifnet_unit(ifp));
+ }
+ vlp->vlp_signature = 0;
+ FREE(vlp, M_VLAN);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+/*
+ * Function: vlan_parent_wait
+ * Purpose:
+ * Allows a single thread to gain exclusive access to the vlan_parent
+ * data structure. Some operations take a long time to complete,
+ * and some have side-effects that we can't predict. Holding the
+ * vlan_lock() across such operations is not possible.
+ *
+ * Notes:
+ * Before calling, you must be holding the vlan_lock and have taken
+ * a reference on the vlan_parent_ref.
+ */
+static void
+vlan_parent_wait(vlan_parent_ref vlp, const char * msg)
+{
+ int waited = 0;
+
+ /* other add/remove/multicast-change in progress */
+ while (vlan_parent_flags_change_in_progress(vlp)) {
+ if (g_vlan->verbose) {
+ struct ifnet * ifp = vlp->vlp_ifp;
+
+ printf("%s%d: %s msleep\n", ifnet_name(ifp), ifnet_unit(ifp), msg);
+ }
+ waited = 1;
+ (void)msleep(vlp, vlan_lck_mtx, PZERO, msg, 0);
+ }
+ /* prevent other vlan parent remove/add from taking place */
+ vlan_parent_flags_set_change_in_progress(vlp);
+ if (g_vlan->verbose && waited) {
+ struct ifnet * ifp = vlp->vlp_ifp;
+
+ printf("%s%d: %s woke up\n", ifnet_name(ifp), ifnet_unit(ifp), msg);
+ }
+ return;
+}
+
+/*
+ * Function: vlan_parent_signal
+ * Purpose:
+ * Allows the thread that previously invoked vlan_parent_wait() to
+ * give up exclusive access to the vlan_parent data structure, and wake up
+ * any other threads waiting to access
+ * Notes:
+ * Before calling, you must be holding the vlan_lock and have taken
+ * a reference on the vlan_parent_ref.
+ */
+static void
+vlan_parent_signal(vlan_parent_ref vlp, const char * msg)
+{
+ struct ifnet * vlp_ifp = vlp->vlp_ifp;
+
+ if (vlan_parent_flags_link_event_required(vlp)) {
+ vlan_parent_flags_clear_link_event_required(vlp);
+ if (!vlan_parent_flags_detaching(vlp)) {
+ u_int32_t event_code = vlp->vlp_event_code;
+ ifvlan_ref ifv;
+
+ vlan_unlock();
+
+ /* we can safely walk the list unlocked */
+ LIST_FOREACH(ifv, &vlp->vlp_vlan_list, ifv_vlan_list) {
+ struct ifnet * ifp = ifv->ifv_ifp;
+
+ interface_link_event(ifp, event_code);
+ }
+ if (g_vlan->verbose) {
+ printf("%s%d: propagated link event to vlans\n",
+ ifnet_name(vlp_ifp), ifnet_unit(vlp_ifp));
+ }
+ vlan_lock();
+ }