]>
Commit | Line | Data |
---|---|---|
b0d623f7 | 1 | /* |
cb323159 | 2 | * Copyright (c) 2008,2011,2019 Apple Inc. All rights reserved. |
b0d623f7 A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
0a7de745 | 5 | * |
b0d623f7 A |
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. | |
0a7de745 | 14 | * |
b0d623f7 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
b0d623f7 A |
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. | |
0a7de745 | 25 | * |
b0d623f7 A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
28 | ||
29 | #include <sys/types.h> | |
30 | #include <kern/locks.h> | |
f427ee49 | 31 | #include <kern/zalloc.h> |
b0d623f7 A |
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 | ||
f427ee49 | 44 | #define NET_ID_STR_MAX_LEN 2048 |
0a7de745 | 45 | #define NET_ID_STR_ENTRY_SIZE(__str) \ |
cb323159 | 46 | (__builtin_offsetof(struct net_str_id_entry, nsi_string[0]) + \ |
b0d623f7 A |
47 | strlen(__str) + 1) |
48 | ||
0a7de745 A |
49 | #define FIRST_NET_STR_ID 1000 |
50 | static SLIST_HEAD(, net_str_id_entry) net_str_id_list = {NULL}; | |
316670eb | 51 | decl_lck_mtx_data(static, net_str_id_lock_data); |
0a7de745 | 52 | static lck_mtx_t *net_str_id_lock = &net_str_id_lock_data; |
b0d623f7 A |
53 | |
54 | static u_int32_t nsi_kind_next[NSI_MAX_KIND] = { FIRST_NET_STR_ID, FIRST_NET_STR_ID, FIRST_NET_STR_ID }; | |
55 | static u_int32_t nsi_next_id = FIRST_NET_STR_ID; | |
56 | ||
b0d623f7 A |
57 | extern int sysctl_if_family_ids SYSCTL_HANDLER_ARGS; |
58 | ||
59 | SYSCTL_DECL(_net_link_generic_system); | |
60 | ||
61 | SYSCTL_PROC(_net_link_generic_system, OID_AUTO, if_family_ids, CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED, | |
0a7de745 | 62 | 0, 0, sysctl_if_family_ids, "S, if_family_id", "Interface Family ID table"); |
b0d623f7 | 63 | |
b0d623f7 A |
64 | __private_extern__ void |
65 | net_str_id_init(void) | |
66 | { | |
0a7de745 A |
67 | lck_grp_attr_t *grp_attrib = NULL; |
68 | lck_attr_t *lck_attrb = NULL; | |
69 | lck_grp_t *lck_group = NULL; | |
70 | ||
b0d623f7 A |
71 | grp_attrib = lck_grp_attr_alloc_init(); |
72 | lck_group = lck_grp_alloc_init("mbuf_tag_allocate_id", grp_attrib); | |
73 | lck_grp_attr_free(grp_attrib); | |
74 | lck_attrb = lck_attr_alloc_init(); | |
0a7de745 | 75 | |
316670eb | 76 | lck_mtx_init(net_str_id_lock, lck_group, lck_attrb); |
0a7de745 | 77 | |
b0d623f7 A |
78 | lck_grp_free(lck_group); |
79 | lck_attr_free(lck_attrb); | |
80 | } | |
81 | ||
82 | __private_extern__ void | |
83 | net_str_id_first_last(u_int32_t *first, u_int32_t *last, u_int32_t kind) | |
84 | { | |
85 | *first = FIRST_NET_STR_ID; | |
86 | ||
87 | switch (kind) { | |
0a7de745 A |
88 | case NSI_MBUF_TAG: |
89 | case NSI_VENDOR_CODE: | |
90 | case NSI_IF_FAM_ID: | |
91 | *last = nsi_kind_next[kind] - 1; | |
92 | break; | |
93 | default: | |
94 | *last = FIRST_NET_STR_ID - 1; | |
95 | break; | |
b0d623f7 A |
96 | } |
97 | } | |
98 | ||
99 | __private_extern__ errno_t | |
f427ee49 A |
100 | net_str_id_find_internal(const char *string, u_int32_t *out_id, |
101 | u_int32_t kind, int create) | |
b0d623f7 | 102 | { |
0a7de745 A |
103 | struct net_str_id_entry *entry = NULL; |
104 | ||
105 | ||
106 | if (string == NULL || out_id == NULL || kind >= NSI_MAX_KIND) { | |
b0d623f7 | 107 | return EINVAL; |
0a7de745 | 108 | } |
f427ee49 A |
109 | if (strlen(string) > NET_ID_STR_MAX_LEN) { |
110 | return EINVAL; | |
111 | } | |
b0d623f7 A |
112 | |
113 | *out_id = 0; | |
0a7de745 | 114 | |
b0d623f7 A |
115 | /* Look for an existing entry */ |
116 | lck_mtx_lock(net_str_id_lock); | |
117 | SLIST_FOREACH(entry, &net_str_id_list, nsi_next) { | |
118 | if (strcmp(string, entry->nsi_string) == 0) { | |
119 | break; | |
120 | } | |
121 | } | |
0a7de745 | 122 | |
b0d623f7 A |
123 | if (entry == NULL) { |
124 | if (create == 0) { | |
125 | lck_mtx_unlock(net_str_id_lock); | |
126 | return ENOENT; | |
127 | } | |
0a7de745 | 128 | |
f427ee49 A |
129 | entry = zalloc_permanent(NET_ID_STR_ENTRY_SIZE(string), |
130 | ZALIGN_PTR); | |
b0d623f7 A |
131 | if (entry == NULL) { |
132 | lck_mtx_unlock(net_str_id_lock); | |
133 | return ENOMEM; | |
134 | } | |
0a7de745 | 135 | |
b0d623f7 A |
136 | strlcpy(entry->nsi_string, string, strlen(string) + 1); |
137 | entry->nsi_flags = (1 << kind); | |
138 | entry->nsi_id = nsi_next_id++; | |
139 | nsi_kind_next[kind] = nsi_next_id; | |
140 | SLIST_INSERT_HEAD(&net_str_id_list, entry, nsi_next); | |
141 | } else if ((entry->nsi_flags & (1 << kind)) == 0) { | |
142 | if (create == 0) { | |
143 | lck_mtx_unlock(net_str_id_lock); | |
144 | return ENOENT; | |
145 | } | |
146 | entry->nsi_flags |= (1 << kind); | |
0a7de745 | 147 | if (entry->nsi_id >= nsi_kind_next[kind]) { |
b0d623f7 | 148 | nsi_kind_next[kind] = entry->nsi_id + 1; |
0a7de745 | 149 | } |
b0d623f7 A |
150 | } |
151 | lck_mtx_unlock(net_str_id_lock); | |
152 | ||
153 | *out_id = entry->nsi_id; | |
0a7de745 | 154 | |
b0d623f7 A |
155 | return 0; |
156 | } | |
157 | ||
158 | ||
b0d623f7 | 159 | #define ROUNDUP32(a) \ |
0a7de745 | 160 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t)) |
b0d623f7 A |
161 | |
162 | int | |
163 | sysctl_if_family_ids SYSCTL_HANDLER_ARGS /* XXX bad syntax! */ | |
164 | { | |
165 | #pragma unused(oidp) | |
166 | #pragma unused(arg1) | |
167 | #pragma unused(arg2) | |
0a7de745 | 168 | errno_t error = 0; |
b0d623f7 A |
169 | struct net_str_id_entry *entry = NULL; |
170 | struct if_family_id *iffmid = NULL; | |
171 | size_t max_size = 0; | |
0a7de745 | 172 | |
b0d623f7 A |
173 | lck_mtx_lock(net_str_id_lock); |
174 | SLIST_FOREACH(entry, &net_str_id_list, nsi_next) { | |
175 | size_t str_size; | |
176 | size_t iffmid_size; | |
0a7de745 A |
177 | |
178 | if ((entry->nsi_flags & (1 << NSI_IF_FAM_ID)) == 0) { | |
b0d623f7 | 179 | continue; |
0a7de745 A |
180 | } |
181 | ||
f427ee49 A |
182 | str_size = strlen(entry->nsi_string); |
183 | if (str_size > NET_ID_STR_MAX_LEN) { | |
184 | str_size = NET_ID_STR_MAX_LEN; | |
185 | } | |
186 | str_size += 1; // make room for end-of-string | |
b0d623f7 A |
187 | iffmid_size = ROUNDUP32(offsetof(struct net_str_id_entry, nsi_string) + str_size); |
188 | ||
189 | if (iffmid_size > max_size) { | |
0a7de745 | 190 | if (iffmid) { |
b0d623f7 | 191 | _FREE(iffmid, M_TEMP); |
0a7de745 | 192 | } |
b0d623f7 A |
193 | iffmid = _MALLOC(iffmid_size, M_TEMP, M_WAITOK); |
194 | if (iffmid == NULL) { | |
195 | lck_mtx_unlock(net_str_id_lock); | |
196 | error = ENOMEM; | |
197 | goto done; | |
198 | } | |
199 | max_size = iffmid_size; | |
200 | } | |
201 | ||
202 | bzero(iffmid, iffmid_size); | |
f427ee49 | 203 | iffmid->iffmid_len = (uint32_t)iffmid_size; |
b0d623f7 A |
204 | iffmid->iffmid_id = entry->nsi_id; |
205 | strlcpy(iffmid->iffmid_str, entry->nsi_string, str_size); | |
0a7de745 A |
206 | error = SYSCTL_OUT(req, iffmid, iffmid_size); |
207 | if (error) { | |
b0d623f7 A |
208 | lck_mtx_unlock(net_str_id_lock); |
209 | goto done; | |
0a7de745 | 210 | } |
b0d623f7 A |
211 | } |
212 | lck_mtx_unlock(net_str_id_lock); | |
0a7de745 | 213 | |
b0d623f7 | 214 | done: |
0a7de745 | 215 | if (iffmid) { |
b0d623f7 | 216 | _FREE(iffmid, M_TEMP); |
0a7de745 | 217 | } |
b0d623f7 A |
218 | return error; |
219 | } |