+static int
+if_add_netagent_locked(struct ifnet *ifp, uuid_t new_agent_uuid)
+{
+ uuid_t *first_empty_slot = NULL;
+ u_int32_t index = 0;
+ bool already_added = FALSE;
+
+ if (ifp->if_agentids != NULL) {
+ for (index = 0; index < ifp->if_agentcount; index++) {
+ uuid_t *netagent_uuid = &(ifp->if_agentids[index]);
+ if (uuid_compare(*netagent_uuid, new_agent_uuid) == 0) {
+ /* Already present, ignore */
+ already_added = TRUE;
+ break;
+ }
+ if (first_empty_slot == NULL &&
+ uuid_is_null(*netagent_uuid)) {
+ first_empty_slot = netagent_uuid;
+ }
+ }
+ }
+ if (already_added) {
+ /* Already added agent, don't return an error */
+ return (0);
+ }
+ if (first_empty_slot == NULL) {
+ if (ifp->if_agentcount >= IF_MAXAGENTS) {
+ /* No room for another netagent UUID, bail */
+ return (ENOMEM);
+ } else {
+ /* Calculate new array size */
+ u_int32_t new_agent_count =
+ MIN(ifp->if_agentcount + IF_AGENT_INCREMENT,
+ IF_MAXAGENTS);
+
+ /* Reallocate array */
+ uuid_t *new_agent_array = _REALLOC(ifp->if_agentids,
+ sizeof(uuid_t) * new_agent_count, M_NETAGENT,
+ M_WAITOK | M_ZERO);
+ if (new_agent_array == NULL) {
+ return (ENOMEM);
+ }
+
+ /* Save new array */
+ ifp->if_agentids = new_agent_array;
+
+ /* Set first empty slot */
+ first_empty_slot =
+ &(ifp->if_agentids[ifp->if_agentcount]);
+
+ /* Save new array length */
+ ifp->if_agentcount = new_agent_count;
+ }
+ }
+ uuid_copy(*first_empty_slot, new_agent_uuid);
+ netagent_post_updated_interfaces(new_agent_uuid);
+ return (0);
+}
+
+int
+if_add_netagent(struct ifnet *ifp, uuid_t new_agent_uuid)
+{
+ VERIFY(ifp != NULL);
+
+ ifnet_lock_exclusive(ifp);
+
+ int error = if_add_netagent_locked(ifp, new_agent_uuid);
+
+ ifnet_lock_done(ifp);
+
+ return (error);
+}
+
+static int
+if_delete_netagent_locked(struct ifnet *ifp, uuid_t remove_agent_uuid)
+{
+ u_int32_t index = 0;
+ bool removed_agent_id = FALSE;
+
+ if (ifp->if_agentids != NULL) {
+ for (index = 0; index < ifp->if_agentcount; index++) {
+ uuid_t *netagent_uuid = &(ifp->if_agentids[index]);
+ if (uuid_compare(*netagent_uuid,
+ remove_agent_uuid) == 0) {
+ uuid_clear(*netagent_uuid);
+ removed_agent_id = TRUE;
+ break;
+ }
+ }
+ }
+ if (removed_agent_id)
+ netagent_post_updated_interfaces(remove_agent_uuid);
+
+ return (0);
+}
+
+int
+if_delete_netagent(struct ifnet *ifp, uuid_t remove_agent_uuid)
+{
+ VERIFY(ifp != NULL);
+
+ ifnet_lock_exclusive(ifp);
+
+ int error = if_delete_netagent_locked(ifp, remove_agent_uuid);
+
+ ifnet_lock_done(ifp);
+
+ return (error);
+}
+