5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2013 Joyent, Inc. All rights reserved.
26 * Copyright (c) 2016 by Delphix. All rights reserved.
27 */
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/errno.h>
32 #include <sys/kmem.h>
33 #include <sys/mutex.h>
34 #include <sys/condvar.h>
35 #include <sys/modctl.h>
36 #include <sys/hook_impl.h>
37 #include <sys/sdt.h>
38 #include <sys/cmn_err.h>
39
40 /*
41 * This file provides kernel hook framework.
42 */
43
44 static struct modldrv modlmisc = {
45 &mod_miscops, /* drv_modops */
690 return (error);
691 }
692
693 /*
694 * Function: hook_stack_notify_unregister
695 * Returns: int - 0 = success, else failure
696 * Parameters: stackid(I) - netstack identifier
697 * callback(I) - function to be called
698 *
699 * Attempt to remove a registered function from a hook stack's list of
700 * callbacks to activiate when protocols are added/deleted.
701 * As with hook_stack_notify_register, if all things are going well then
702 * a fake unregister event is delivered to the callback being removed
703 * for each hook family that presently exists.
704 */
705 int
706 hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback)
707 {
708 hook_family_int_t *hfi;
709 hook_stack_t *hks;
710 boolean_t canrun;
711 char buffer[16];
712 void *arg;
713 int error;
714
715 mutex_enter(&hook_stack_lock);
716 hks = hook_stack_get(stackid);
717 if (hks != NULL) {
718 CVW_ENTER_WRITE(&hks->hks_lock);
719 canrun = (hook_wait_setflag(&hks->hks_waiter, FWF_ADD_WAIT_MASK,
720 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
721
722 error = hook_notify_unregister(&hks->hks_nhead, callback, &arg);
723 CVW_EXIT_WRITE(&hks->hks_lock);
724 } else {
725 error = ESRCH;
726 }
727 mutex_exit(&hook_stack_lock);
728
729 if (error == 0) {
730 if (canrun) {
731 /*
732 * Generate fake unregister event for callback that
733 * is being removed, letting it know everything that
734 * currently exists is now "disappearing."
735 */
736 (void) snprintf(buffer, sizeof (buffer), "%u",
737 hks->hks_netstackid);
738
739 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
740 callback(HN_UNREGISTER, arg, buffer, NULL,
741 hfi->hfi_family.hf_name);
742 }
743
744 hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
745 }
746
747 mutex_enter(&hook_stack_lock);
748 hks = hook_stack_get(stackid);
749 if ((error == 0) && (hks->hks_shutdown == 2))
750 hook_stack_remove(hks);
751 mutex_exit(&hook_stack_lock);
752 }
753
754 return (error);
755 }
756
757 /*
758 * Function: hook_stack_notify_run
759 * Returns: None
760 * Parameters: hks(I) - hook stack pointer to execute callbacks for
761 * name(I) - name of a hook family
762 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
763 *
764 * Run through the list of callbacks on the hook stack to be called when
765 * a new hook family is added
766 *
767 * As hook_notify_run() expects 3 names, one for the family that is associated
768 * with the cmd (HN_REGISTER or HN_UNREGISTER), one for the event and one
769 * for the object being introduced and we really only have one name (that
770 * of the new hook family), fake the hook stack's name by converting the
771 * integer to a string and for the event just pass NULL.
772 */
|
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2018 Joyent, Inc. All rights reserved.
26 * Copyright (c) 2016 by Delphix. All rights reserved.
27 */
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/errno.h>
32 #include <sys/kmem.h>
33 #include <sys/mutex.h>
34 #include <sys/condvar.h>
35 #include <sys/modctl.h>
36 #include <sys/hook_impl.h>
37 #include <sys/sdt.h>
38 #include <sys/cmn_err.h>
39
40 /*
41 * This file provides kernel hook framework.
42 */
43
44 static struct modldrv modlmisc = {
45 &mod_miscops, /* drv_modops */
690 return (error);
691 }
692
693 /*
694 * Function: hook_stack_notify_unregister
695 * Returns: int - 0 = success, else failure
696 * Parameters: stackid(I) - netstack identifier
697 * callback(I) - function to be called
698 *
699 * Attempt to remove a registered function from a hook stack's list of
700 * callbacks to activiate when protocols are added/deleted.
701 * As with hook_stack_notify_register, if all things are going well then
702 * a fake unregister event is delivered to the callback being removed
703 * for each hook family that presently exists.
704 */
705 int
706 hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback)
707 {
708 hook_family_int_t *hfi;
709 hook_stack_t *hks;
710 char buffer[16];
711 void *arg;
712 int error;
713
714 mutex_enter(&hook_stack_lock);
715 hks = hook_stack_get(stackid);
716 if (hks == NULL) {
717 mutex_exit(&hook_stack_lock);
718 return (ESRCH);
719 }
720
721 CVW_ENTER_WRITE(&hks->hks_lock);
722 /*
723 * If hook_wait_setflag returns -1, another thread has flagged that it
724 * is attempting to destroy this hook stack. Before it can flag that
725 * it's destroying the hook stack, it must first verify (with
726 * hook_stack_lock held) that the hook stack is empty. If we
727 * encounter this, it means we should have nothing to do and we
728 * just snuck in.
729 */
730 if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
731 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
732 VERIFY(TAILQ_EMPTY(&hks->hks_nhead));
733 CVW_EXIT_WRITE(&hks->hks_lock);
734 mutex_exit(&hook_stack_lock);
735 return (ESRCH);
736 }
737
738 error = hook_notify_unregister(&hks->hks_nhead, callback, &arg);
739 CVW_EXIT_WRITE(&hks->hks_lock);
740 mutex_exit(&hook_stack_lock);
741
742 if (error == 0) {
743 /*
744 * Generate fake unregister event for callback that
745 * is being removed, letting it know everything that
746 * currently exists is now "disappearing."
747 */
748 (void) snprintf(buffer, sizeof (buffer), "%u",
749 hks->hks_netstackid);
750
751 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
752 callback(HN_UNREGISTER, arg, buffer, NULL,
753 hfi->hfi_family.hf_name);
754 }
755 } else {
756 /*
757 * hook_notify_unregister() should only fail if the callback has
758 * already been deleted (ESRCH).
759 */
760 VERIFY3S(error, ==, ESRCH);
761 }
762
763 mutex_enter(&hook_stack_lock);
764 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
765 if (hks->hks_shutdown == 2)
766 hook_stack_remove(hks);
767 mutex_exit(&hook_stack_lock);
768
769 return (error);
770 }
771
772 /*
773 * Function: hook_stack_notify_run
774 * Returns: None
775 * Parameters: hks(I) - hook stack pointer to execute callbacks for
776 * name(I) - name of a hook family
777 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
778 *
779 * Run through the list of callbacks on the hook stack to be called when
780 * a new hook family is added
781 *
782 * As hook_notify_run() expects 3 names, one for the family that is associated
783 * with the cmd (HN_REGISTER or HN_UNREGISTER), one for the event and one
784 * for the object being introduced and we really only have one name (that
785 * of the new hook family), fake the hook stack's name by converting the
786 * integer to a string and for the event just pass NULL.
787 */
|