]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/DeviceOnHold.c
88079cfaf829a4d41480e39c8885c1ac61082bcb
[apple/configd.git] / SystemConfiguration.fproj / DeviceOnHold.c
1 /*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 /*
24 * Modification History
25 *
26 * May 29, 2002 Roger Smith <rsmith@apple.com>
27 * - initial revision
28 */
29
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <mach/mach.h>
34 #include <mach-o/dyld.h>
35 #include <pthread.h>
36
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <CoreFoundation/CFRuntime.h>
39
40 #include <SystemConfiguration/SystemConfiguration.h>
41 #include <SystemConfiguration/SCValidation.h>
42 #include <SystemConfiguration/SCPrivate.h>
43
44 #include <IOKit/IOKitLib.h>
45
46 #include "moh_msg.h"
47 #include "moh.h"
48 #include "DeviceOnHold.h"
49
50
51 #define kIODeviceSupportsHoldKey "DeviceSupportsHold"
52
53
54 static void *
55 __loadIOKit(void) {
56 static const void *image = NULL;
57 if (NULL == image) {
58 const char *framework = "/System/Library/Frameworks/IOKit.framework/IOKit";
59 struct stat statbuf;
60 const char *suffix = getenv("DYLD_IMAGE_SUFFIX");
61 char path[MAXPATHLEN];
62
63 strcpy(path, framework);
64 if (suffix) strcat(path, suffix);
65 if (0 <= stat(path, &statbuf)) {
66 image = NSAddImage(path, NSADDIMAGE_OPTION_NONE);
67 } else {
68 image = NSAddImage(framework, NSADDIMAGE_OPTION_NONE);
69 }
70 }
71 return (void *)image;
72 }
73
74
75 static io_object_t
76 _IOIteratorNext(io_iterator_t iterator)
77 {
78 static io_object_t (*dyfunc)(io_iterator_t) = NULL;
79 if (!dyfunc) {
80 void *image = __loadIOKit();
81 if (image) dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "_IOIteratorNext", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
82 }
83 return dyfunc ? dyfunc(iterator) : 0;
84 }
85 #define IOIteratorNext _IOIteratorNext
86
87
88 static kern_return_t
89 _IOMasterPort(mach_port_t bootstrapPort, mach_port_t *masterPort)
90 {
91 static kern_return_t (*dyfunc)(mach_port_t, mach_port_t *) = NULL;
92 if (!dyfunc) {
93 void *image = __loadIOKit();
94 if (image) dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "_IOMasterPort", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
95 }
96 return dyfunc ? dyfunc(bootstrapPort, masterPort) : KERN_FAILURE;
97 }
98 #define IOMasterPort _IOMasterPort
99
100
101 static kern_return_t
102 _IOObjectRelease(io_object_t object)
103 {
104 static kern_return_t (*dyfunc)(io_object_t) = NULL;
105 if (!dyfunc) {
106 void *image = __loadIOKit();
107 if (image) dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "_IOObjectRelease", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
108 }
109 return dyfunc ? dyfunc(object) : KERN_FAILURE;
110 }
111 #define IOObjectRelease _IOObjectRelease
112
113
114 static kern_return_t
115 _IORegistryEntryCreateCFProperties(io_registry_entry_t entry, CFMutableDictionaryRef *properties, CFAllocatorRef allocator, IOOptionBits options)
116 {
117 static kern_return_t (*dyfunc)(io_registry_entry_t, CFMutableDictionaryRef *, CFAllocatorRef, IOOptionBits) = NULL;
118 if (!dyfunc) {
119 void *image = __loadIOKit();
120 if (image) dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "_IORegistryEntryCreateCFProperties", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
121 }
122 return dyfunc ? dyfunc(entry, properties, allocator, options) : KERN_FAILURE;
123 }
124 #define IORegistryEntryCreateCFProperties _IORegistryEntryCreateCFProperties
125
126
127 static kern_return_t
128 _IORegistryEntryGetPath(io_registry_entry_t entry, const io_name_t plane, io_string_t path)
129 {
130 static kern_return_t (*dyfunc)(io_registry_entry_t, const io_name_t, io_string_t) = NULL;
131 if (!dyfunc) {
132 void *image = __loadIOKit();
133 if (image) dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "_IORegistryEntryGetPath", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
134 }
135 return dyfunc ? dyfunc(entry, plane, path) : KERN_FAILURE;
136 }
137 #define IORegistryEntryGetPath _IORegistryEntryGetPath
138
139
140 static kern_return_t
141 _IOServiceGetMatchingServices(mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t *existing)
142 {
143 static kern_return_t (*dyfunc)(mach_port_t, CFDictionaryRef, io_iterator_t *) = NULL;
144 if (!dyfunc) {
145 void *image = __loadIOKit();
146 if (image) dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "_IOServiceGetMatchingServices", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
147 }
148 return dyfunc ? dyfunc(masterPort, matching, existing) : KERN_FAILURE;
149 }
150 #define IOServiceGetMatchingServices _IOServiceGetMatchingServices
151
152
153 static CFMutableDictionaryRef
154 _IOServiceMatching(const char *name)
155 {
156 static CFMutableDictionaryRef (*dyfunc)(const char *) = NULL;
157 if (!dyfunc) {
158 void *image = __loadIOKit();
159 if (image) dyfunc = NSAddressOfSymbol(NSLookupSymbolInImage(image, "_IOServiceMatching", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND));
160 }
161 return dyfunc ? dyfunc(name) : NULL;
162 }
163 #define IOServiceMatching _IOServiceMatching
164
165
166 typedef struct {
167
168 /* base CFType information */
169 CFRuntimeBase cfBase;
170
171 /* device name (e.g. "modem") */
172 CFStringRef name;
173
174 int sock;
175
176 } DeviceOnHoldPrivate, *DeviceOnHoldPrivateRef;
177
178
179 static CFStringRef
180 __DeviceOnHoldCopyDescription(CFTypeRef cf)
181 {
182 CFAllocatorRef allocator = CFGetAllocator(cf);
183 CFMutableStringRef result;
184
185 result = CFStringCreateMutable(allocator, 0);
186 CFStringAppendFormat(result, NULL, CFSTR("<DeviceOnHold %p [%p]> {\n"), cf, allocator);
187 CFStringAppendFormat(result, NULL, CFSTR("}"));
188
189 return result;
190 }
191
192
193 static void
194 __DeviceOnHoldDeallocate(CFTypeRef cf)
195 {
196 DeviceOnHoldPrivateRef DeviceOnHoldPrivate = (DeviceOnHoldPrivateRef)cf;
197
198 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__DeviceOnHoldDeallocate:"));
199
200 /* release resources */
201 if (DeviceOnHoldPrivate->name) CFRelease(DeviceOnHoldPrivate->name);
202 if (DeviceOnHoldPrivate->sock != -1) {
203
204 }
205
206 return;
207 }
208
209
210 static CFTypeID __kDeviceOnHoldTypeID = _kCFRuntimeNotATypeID;
211
212
213 static const CFRuntimeClass __DeviceOnHoldClass = {
214 0, // version
215 "DeviceOnHold", // className
216 NULL, // init
217 NULL, // copy
218 __DeviceOnHoldDeallocate, // dealloc
219 NULL, // equal
220 NULL, // hash
221 NULL, // copyFormattingDesc
222 __DeviceOnHoldCopyDescription // copyDebugDesc
223 };
224
225
226 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
227
228
229 static void
230 __DeviceOnHoldInitialize(void)
231 {
232 __kDeviceOnHoldTypeID = _CFRuntimeRegisterClass(&__DeviceOnHoldClass);
233 return;
234 }
235
236
237 DeviceOnHoldRef
238 __DeviceOnHoldCreatePrivate(CFAllocatorRef allocator)
239 {
240 DeviceOnHoldPrivateRef devicePrivate;
241 UInt32 size;
242
243 /* initialize runtime */
244 pthread_once(&initialized, __DeviceOnHoldInitialize);
245
246 /* allocate session */
247 size = sizeof(DeviceOnHoldPrivate) - sizeof(CFRuntimeBase);
248 devicePrivate = (DeviceOnHoldPrivateRef)_CFRuntimeCreateInstance(allocator,
249 __kDeviceOnHoldTypeID,
250 size,
251 NULL);
252 if (!devicePrivate) {
253 return NULL;
254 }
255
256 devicePrivate->name = NULL;
257 devicePrivate->sock = -1;
258
259 return (DeviceOnHoldRef)devicePrivate;
260 }
261
262
263 /*
264 * TBD: We determine whether a device supports on hold capability by looking at
265 * the numeric property DeviceSupportsHold (1 - yes, 0 or no property - no). For
266 * the Apple Dash II internal modem we also use the property V92Modem to track
267 * this same capability.
268 */
269
270 Boolean
271 IsDeviceOnHoldSupported(CFStringRef deviceName, // "modem"
272 CFDictionaryRef options)
273 {
274 CFMutableDictionaryRef deviceToMatch;
275 u_int32_t deviceSupportsHoldValue;
276 kern_return_t kr;
277 mach_port_t masterPort;
278 io_iterator_t matchingServices;
279 CFNumberRef num;
280 CFMutableDictionaryRef properties;
281 Boolean result = FALSE;
282 io_service_t service;
283
284 if (CFStringCompare(deviceName, CFSTR("modem"), NULL) == kCFCompareEqualTo) {
285 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
286 if (kr != KERN_SUCCESS) {
287 goto errorExit;
288 }
289
290 deviceToMatch = IOServiceMatching("InternalModemSupport");
291 if (!deviceToMatch) {
292 goto errorExit;
293 }
294
295 kr = IOServiceGetMatchingServices(masterPort, deviceToMatch, &matchingServices);
296 if (kr != KERN_SUCCESS) {
297 goto errorExit;
298 }
299
300 for ( ; service = IOIteratorNext(matchingServices) ; IOObjectRelease(service)) {
301 io_string_t path;
302
303 kr = IORegistryEntryGetPath(service, kIOServicePlane, path);
304 assert( kr == KERN_SUCCESS );
305
306 // grab a copy of the properties
307 kr = IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, kNilOptions);
308 assert( kr == KERN_SUCCESS );
309
310 num = CFDictionaryGetValue(properties, CFSTR(kIODeviceSupportsHoldKey));
311 if (isA_CFNumber(num)) {
312 CFNumberGetValue(num, kCFNumberSInt32Type, &deviceSupportsHoldValue);
313 if (deviceSupportsHoldValue == 1) {
314 result = TRUE;
315 }
316 }
317
318 CFRelease(properties);
319 }
320
321 IOObjectRelease(matchingServices);
322 }
323
324 // Note: The issue for the general case is how to go from the SystemConfiguration
325 // dynamic store to the actual driver. The devicesupportshold property is not
326 // copied the either of the setup/state descriptions so the caller would need
327 // to know the exact driver they are searching for.
328
329 return result;
330
331 errorExit:
332
333 return FALSE;
334 }
335
336
337 DeviceOnHoldRef
338 DeviceOnHoldCreate(CFAllocatorRef allocator,
339 CFStringRef deviceName, // "modem"
340 CFDictionaryRef options)
341 {
342 DeviceOnHoldRef device = NULL;
343 DeviceOnHoldPrivateRef devicePrivate;
344 int status;
345
346 if (CFStringCompare(deviceName, CFSTR("modem"), NULL) != kCFCompareEqualTo) {
347 return NULL;
348 }
349
350 device = __DeviceOnHoldCreatePrivate(allocator);
351 if (!device) {
352 return NULL;
353 }
354
355 devicePrivate = (DeviceOnHoldPrivateRef)device;
356
357 status = MOHInit(&devicePrivate->sock, deviceName);
358 if (status != 0) {
359 CFRelease(device);
360 return NULL;
361 }
362
363 devicePrivate->name = CFRetain(deviceName);
364
365 return device;
366 }
367
368
369
370 int32_t
371 DeviceOnHoldGetStatus(DeviceOnHoldRef device)
372 {
373 DeviceOnHoldPrivateRef devicePrivate = (DeviceOnHoldPrivateRef)device;
374 int err;
375 u_long link = 1;
376 void *replyBuf;
377 u_long replyBufLen;
378 int32_t result = -1;
379
380 if (!device) {
381 return -1;
382 }
383
384 if (devicePrivate->sock == -1) {
385 return -1;
386 }
387
388 err = MOHExec(devicePrivate->sock,
389 link,
390 MOH_SESSION_GET_STATUS,
391 NULL,
392 0,
393 &replyBuf,
394 &replyBufLen);
395
396 if (err != 0) {
397 return -1;
398 }
399
400 if (replyBufLen == sizeof(result)) {
401 result = *(int32_t *)replyBuf;
402 }
403
404 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
405 return result;
406 }
407
408
409 Boolean
410 DeviceOnHoldSuspend(DeviceOnHoldRef device)
411 {
412 DeviceOnHoldPrivateRef devicePrivate = (DeviceOnHoldPrivateRef)device;
413 int err;
414 u_long link = 1;
415 void *replyBuf;
416 u_long replyBufLen;
417 Boolean result = FALSE;
418
419 if (!device) {
420 return FALSE;
421 }
422
423 if (devicePrivate->sock == -1) {
424 return FALSE;
425 }
426
427 err = MOHExec(devicePrivate->sock,
428 link,
429 MOH_PUT_SESSION_ON_HOLD,
430 NULL,
431 0,
432 &replyBuf,
433 &replyBufLen);
434
435 if (err != 0) {
436 return -1;
437 }
438
439 if (replyBufLen == sizeof(result)) {
440 result = (*(int32_t *)replyBuf) ? TRUE : FALSE;
441 }
442
443 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
444 return result;
445 }
446
447
448 Boolean
449 DeviceOnHoldResume(DeviceOnHoldRef device)
450 {
451 DeviceOnHoldPrivateRef devicePrivate = (DeviceOnHoldPrivateRef)device;
452 int err;
453 u_long link = 1;
454 void *replyBuf;
455 u_long replyBufLen;
456 Boolean result = FALSE;
457
458 if (!device) {
459 return FALSE;
460 }
461
462 if (devicePrivate->sock == -1) {
463 return FALSE;
464 }
465
466 err = MOHExec(devicePrivate->sock,
467 link,
468 MOH_RESUME_SESSION_ON_HOLD,NULL,
469 0,
470 &replyBuf,
471 &replyBufLen);
472
473 if (err != 0) {
474 return -1;
475 }
476
477 if (replyBufLen == sizeof(result)) {
478 result = (*(int32_t *)replyBuf) ? TRUE : FALSE;
479 }
480
481 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
482 return result;
483 }