1/* 2 * Copyright (c) 2008,2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <sys/types.h> 30#include <kern/locks.h> 31#include <kern/kalloc.h> 32#include <sys/errno.h> 33#include <sys/sysctl.h> 34#include <sys/malloc.h> 35#include <sys/socket.h> 36#include <libkern/OSAtomic.h> 37#include <libkern/libkern.h> 38#include <net/if.h> 39#include <net/if_mib.h> 40#include <string.h> 41 42#include "net/net_str_id.h" 43 44#define NET_ID_STR_ENTRY_SIZE(__str) \ 45 ((size_t)&(((struct net_str_id_entry*)0)->nsi_string[0]) + \ 46 strlen(__str) + 1) 47 48#define FIRST_NET_STR_ID 1000 49static SLIST_HEAD(,net_str_id_entry) net_str_id_list = {NULL}; 50decl_lck_mtx_data(static, net_str_id_lock_data); 51static lck_mtx_t *net_str_id_lock = &net_str_id_lock_data; 52 53static u_int32_t nsi_kind_next[NSI_MAX_KIND] = { FIRST_NET_STR_ID, FIRST_NET_STR_ID, FIRST_NET_STR_ID }; 54static u_int32_t nsi_next_id = FIRST_NET_STR_ID; 55 56extern int sysctl_if_family_ids SYSCTL_HANDLER_ARGS; 57 58SYSCTL_DECL(_net_link_generic_system); 59 60SYSCTL_PROC(_net_link_generic_system, OID_AUTO, if_family_ids, CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, 61 0, 0, sysctl_if_family_ids, "S, if_family_id", "Interface Family ID table"); 62 63__private_extern__ void 64net_str_id_init(void) 65{ 66 lck_grp_attr_t *grp_attrib = NULL; 67 lck_attr_t *lck_attrb = NULL; 68 lck_grp_t *lck_group = NULL; 69 70 grp_attrib = lck_grp_attr_alloc_init(); 71 lck_group = lck_grp_alloc_init("mbuf_tag_allocate_id", grp_attrib); 72 lck_grp_attr_free(grp_attrib); 73 lck_attrb = lck_attr_alloc_init(); 74 75 lck_mtx_init(net_str_id_lock, lck_group, lck_attrb); 76 77 lck_grp_free(lck_group); 78 lck_attr_free(lck_attrb); 79} 80 81__private_extern__ void 82net_str_id_first_last(u_int32_t *first, u_int32_t *last, u_int32_t kind) 83{ 84 *first = FIRST_NET_STR_ID; 85 86 switch (kind) { 87 case NSI_MBUF_TAG: 88 case NSI_VENDOR_CODE: 89 case NSI_IF_FAM_ID: 90 *last = nsi_kind_next[kind] - 1; 91 break; 92 default: 93 *last = FIRST_NET_STR_ID - 1; 94 break; 95 } 96} 97 98__private_extern__ errno_t 99net_str_id_find_internal(const char *string, u_int32_t *out_id, 100 u_int32_t kind, int create) 101{ 102 struct net_str_id_entry *entry = NULL; 103 104 105 if (string == NULL || out_id == NULL || kind >= NSI_MAX_KIND) 106 return EINVAL; 107 108 *out_id = 0; 109 110 /* Look for an existing entry */ 111 lck_mtx_lock(net_str_id_lock); 112 SLIST_FOREACH(entry, &net_str_id_list, nsi_next) { 113 if (strcmp(string, entry->nsi_string) == 0) { 114 break; 115 } 116 } 117 118 if (entry == NULL) { 119 if (create == 0) { 120 lck_mtx_unlock(net_str_id_lock); 121 return ENOENT; 122 } 123 124 entry = kalloc(NET_ID_STR_ENTRY_SIZE(string)); 125 if (entry == NULL) { 126 lck_mtx_unlock(net_str_id_lock); 127 return ENOMEM; 128 } 129 130 strlcpy(entry->nsi_string, string, strlen(string) + 1); 131 entry->nsi_flags = (1 << kind); 132 entry->nsi_id = nsi_next_id++; 133 nsi_kind_next[kind] = nsi_next_id; 134 SLIST_INSERT_HEAD(&net_str_id_list, entry, nsi_next); 135 } else if ((entry->nsi_flags & (1 << kind)) == 0) { 136 if (create == 0) { 137 lck_mtx_unlock(net_str_id_lock); 138 return ENOENT; 139 } 140 entry->nsi_flags |= (1 << kind); 141 if (entry->nsi_id >= nsi_kind_next[kind]) 142 nsi_kind_next[kind] = entry->nsi_id + 1; 143 } 144 lck_mtx_unlock(net_str_id_lock); 145 146 *out_id = entry->nsi_id; 147 148 return 0; 149} 150 151 152#define ROUNDUP32(a) \ 153 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t)) 154 155int 156sysctl_if_family_ids SYSCTL_HANDLER_ARGS /* XXX bad syntax! */ 157{ 158#pragma unused(oidp) 159#pragma unused(arg1) 160#pragma unused(arg2) 161 errno_t error = 0; 162 struct net_str_id_entry *entry = NULL; 163 struct if_family_id *iffmid = NULL; 164 size_t max_size = 0; 165 166 lck_mtx_lock(net_str_id_lock); 167 SLIST_FOREACH(entry, &net_str_id_list, nsi_next) { 168 size_t str_size; 169 size_t iffmid_size; 170 171 if ((entry->nsi_flags & (1 << NSI_IF_FAM_ID)) == 0) 172 continue; 173 174 str_size = strlen(entry->nsi_string) + 1; 175 iffmid_size = ROUNDUP32(offsetof(struct net_str_id_entry, nsi_string) + str_size); 176 177 if (iffmid_size > max_size) { 178 if (iffmid) 179 _FREE(iffmid, M_TEMP); 180 iffmid = _MALLOC(iffmid_size, M_TEMP, M_WAITOK); 181 if (iffmid == NULL) { 182 lck_mtx_unlock(net_str_id_lock); 183 error = ENOMEM; 184 goto done; 185 } 186 max_size = iffmid_size; 187 } 188 189 bzero(iffmid, iffmid_size); 190 iffmid->iffmid_len = iffmid_size; 191 iffmid->iffmid_id = entry->nsi_id; 192 strlcpy(iffmid->iffmid_str, entry->nsi_string, str_size); 193 error = SYSCTL_OUT(req, iffmid, iffmid_size); 194 if (error) { 195 lck_mtx_unlock(net_str_id_lock); 196 goto done; 197 } 198 199 } 200 lck_mtx_unlock(net_str_id_lock); 201 202done: 203 if (iffmid) 204 _FREE(iffmid, M_TEMP); 205 return error; 206} 207