--- /dev/null
+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Modification History
+ *
+ * August 5, 2002 Allan Nathanson <ajn@apple.com>
+ * - split code out from eventmon.c
+ */
+
+#include "eventmon.h"
+#include "cache.h"
+#include "ev_appletalk.h"
+
+// from <netat/ddp.h>
+#define DDP_MIN_NETWORK 0x0001
+#define DDP_MAX_NETWORK 0xfffe
+
+
+static int
+get_atalk_interface_cfg(const char *if_name, at_if_cfg_t *cfg)
+{
+ int fd;
+
+ /* open socket */
+ if ((fd = socket(AF_APPLETALK, SOCK_RAW, 0)) < 0)
+ return -1;
+
+ /* get config info for given interface */
+ strncpy(cfg->ifr_name, if_name, sizeof(cfg->ifr_name));
+ if (ioctl(fd, AIOCGETIFCFG, (caddr_t)cfg) < 0) {
+ (void)close(fd);
+ return -1;
+ }
+
+ (void)close(fd);
+ return 0;
+}
+
+
+static CFMutableDictionaryRef
+getIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs)
+{
+ CFDictionaryRef dict = NULL;
+ CFMutableDictionaryRef newDict = NULL;
+
+ if (CFDictionaryGetValueIfPresent(newIFs, key, (const void **)&dict)) {
+ newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+ } else {
+ dict = cache_SCDynamicStoreCopyValue(store, key);
+ if (dict) {
+ CFDictionarySetValue(oldIFs, key, dict);
+ if (isA_CFDictionary(dict)) {
+ newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+ CFDictionaryRemoveValue(newDict, kSCPropNetAppleTalkNetworkID);
+ CFDictionaryRemoveValue(newDict, kSCPropNetAppleTalkNodeID);
+ CFDictionaryRemoveValue(newDict, kSCPropNetAppleTalkNetworkRange);
+ CFDictionaryRemoveValue(newDict, kSCPropNetAppleTalkDefaultZone);
+ }
+ CFRelease(dict);
+ }
+ }
+
+ if (!newDict) {
+ newDict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ return newDict;
+}
+
+
+static void
+updateStore(const void *key, const void *value, void *context)
+{
+ CFDictionaryRef dict;
+ CFDictionaryRef newDict = (CFDictionaryRef)value;
+ CFDictionaryRef oldIFs = (CFDictionaryRef)context;
+
+ dict = CFDictionaryGetValue(oldIFs, key);
+
+ if (!dict || !CFEqual(dict, newDict)) {
+ if (CFDictionaryGetCount(newDict) > 0) {
+ cache_SCDynamicStoreSetValue(store, key, newDict);
+ } else if (dict) {
+ cache_SCDynamicStoreRemoveValue(store, key);
+ }
+ }
+
+ return;
+}
+
+
+__private_extern__
+void
+interface_update_appletalk(struct ifaddrs *ifap, const char *if_name)
+{
+ struct ifaddrs *ifa;
+ struct ifaddrs *ifap_temp = NULL;
+ CFStringRef interface;
+ boolean_t interfaceFound = FALSE;
+ CFStringRef key = NULL;
+ CFMutableDictionaryRef oldIFs;
+ CFMutableDictionaryRef newDict = NULL;
+ CFMutableDictionaryRef newIFs;
+
+ oldIFs = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ newIFs = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ if (!ifap) {
+ if (getifaddrs(&ifap_temp) < 0) {
+ SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
+ goto error;
+ }
+ ifap = ifap_temp;
+ }
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ at_if_cfg_t cfg;
+ int iVal;
+ CFNumberRef num;
+ struct sockaddr_at *sat;
+
+ if (ifa->ifa_addr->sa_family != AF_APPLETALK) {
+ continue; /* sorry, not interested */
+ }
+
+ /* check if this is the requested interface */
+ if (if_name) {
+ if (strncmp(if_name, ifa->ifa_name, IFNAMSIZ) == 0) {
+ interfaceFound = TRUE; /* yes, this is the one I want */
+ } else {
+ continue; /* sorry, not interested */
+ }
+ }
+
+ /* get the current cache information */
+ interface = CFStringCreateWithCString(NULL, ifa->ifa_name, kCFStringEncodingMacRoman);
+ key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+ kSCDynamicStoreDomainState,
+ interface,
+ kSCEntNetAppleTalk);
+ CFRelease(interface);
+
+ newDict = getIF(key, oldIFs, newIFs);
+
+ sat = (struct sockaddr_at *)ifa->ifa_addr;
+
+ iVal = (int)sat->sat_addr.s_net;
+ num = CFNumberCreate(NULL, kCFNumberIntType, &iVal);
+ CFDictionarySetValue(newDict, kSCPropNetAppleTalkNetworkID, num);
+ CFRelease(num);
+
+ iVal = (int)sat->sat_addr.s_node;
+ num = CFNumberCreate(NULL, kCFNumberIntType, &iVal);
+ CFDictionarySetValue(newDict, kSCPropNetAppleTalkNodeID, num);
+ CFRelease(num);
+
+ if (get_atalk_interface_cfg(ifa->ifa_name, &cfg) == 0) {
+ CFStringRef zone;
+
+ /*
+ * Set starting and ending net values
+ */
+ if (!(((cfg.netStart == 0) && (cfg.netEnd == 0)) ||
+ ((cfg.netStart == DDP_MIN_NETWORK) && (cfg.netEnd == DDP_MAX_NETWORK)))) {
+ CFMutableArrayRef array;
+
+ array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ iVal = cfg.netStart;
+ num = CFNumberCreate(NULL, kCFNumberIntType, &iVal);
+ CFArrayAppendValue(array, num);
+ CFRelease(num);
+
+ iVal = cfg.netEnd;
+ num = CFNumberCreate(NULL, kCFNumberIntType, &iVal);
+ CFArrayAppendValue(array, num);
+ CFRelease(num);
+
+ CFDictionarySetValue(newDict, kSCPropNetAppleTalkNetworkRange, array);
+ CFRelease(array);
+ }
+
+ /*
+ * Set the default zone
+ */
+ zone = CFStringCreateWithPascalString(NULL,
+ (ConstStr255Param)&cfg.zonename,
+ kCFStringEncodingMacRoman);
+ CFDictionarySetValue(newDict, kSCPropNetAppleTalkDefaultZone, zone);
+ CFRelease(zone);
+ }
+
+ CFDictionarySetValue(newIFs, key, newDict);
+ CFRelease(newDict);
+ CFRelease(key);
+ }
+
+ /* if the last address[es] were removed from the target interface */
+ if (if_name && !interfaceFound) {
+ interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
+ key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+ kSCDynamicStoreDomainState,
+ interface,
+ kSCEntNetAppleTalk);
+ CFRelease(interface);
+
+ newDict = getIF(key, oldIFs, newIFs);
+
+ CFDictionarySetValue(newIFs, key, newDict);
+ CFRelease(newDict);
+ CFRelease(key);
+ }
+
+ CFDictionaryApplyFunction(newIFs, updateStore, oldIFs);
+
+ error :
+
+ if (ifap_temp) freeifaddrs(ifap_temp);
+ CFRelease(oldIFs);
+ CFRelease(newIFs);
+
+ return;
+}
+
+
+__private_extern__
+void
+interface_update_atalk_address(struct kev_atalk_data *aEvent, const char *if_name)
+{
+ CFStringRef interface;
+ CFStringRef key;
+ CFDictionaryRef dict;
+ CFMutableDictionaryRef newDict = NULL;
+ CFNumberRef newNode, newNet;
+ int node;
+ int net;
+
+ /* get the current cache information */
+ interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
+ key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+ kSCDynamicStoreDomainState,
+ interface,
+ kSCEntNetAppleTalk);
+ CFRelease(interface);
+
+ dict = cache_SCDynamicStoreCopyValue(store, key);
+ if (dict) {
+ if (isA_CFDictionary(dict)) {
+ newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+ }
+ CFRelease(dict);
+ }
+
+ if (!newDict) {
+ newDict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ /* Update node/net values in cache */
+ node = (int)aEvent->node_data.address.s_node;
+ net = (int)aEvent->node_data.address.s_net;
+
+ newNode = CFNumberCreate(NULL, kCFNumberIntType, &node);
+ newNet = CFNumberCreate(NULL, kCFNumberIntType, &net);
+
+ CFDictionarySetValue(newDict, kSCPropNetAppleTalkNodeID, newNode);
+ CFDictionarySetValue(newDict, kSCPropNetAppleTalkNetworkID, newNet);
+
+ CFRelease(newNode);
+ CFRelease(newNet);
+
+ /* update cache */
+ cache_SCDynamicStoreSetValue(store, key, newDict);
+ CFRelease(newDict);
+ CFRelease(key);
+ return;
+}
+
+
+__private_extern__
+void
+interface_update_atalk_zone(struct kev_atalk_data *aEvent, const char *if_name)
+{
+ CFStringRef interface;
+ CFStringRef key;
+ CFDictionaryRef dict;
+ CFMutableDictionaryRef newDict = NULL;
+ CFStringRef newZone;
+
+ /* get the current cache information */
+ interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
+ key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+ kSCDynamicStoreDomainState,
+ interface,
+ kSCEntNetAppleTalk);
+ CFRelease(interface);
+
+ dict = cache_SCDynamicStoreCopyValue(store, key);
+ if (dict) {
+ if (isA_CFDictionary(dict)) {
+ newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+ }
+ CFRelease(dict);
+ }
+
+ if (!newDict) {
+ newDict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ /* Update zone value in cache */
+ newZone = CFStringCreateWithPascalString(NULL, (ConstStr255Param)&(aEvent->node_data.zone), kCFStringEncodingMacRoman);
+
+ CFDictionarySetValue(newDict, kSCPropNetAppleTalkDefaultZone, newZone);
+
+ CFRelease(newZone);
+
+ /* update cache */
+ cache_SCDynamicStoreSetValue(store, key, newDict);
+ CFRelease(newDict);
+ CFRelease(key);
+ return;
+}
+
+
+__private_extern__
+void
+interface_update_shutdown_atalk()
+{
+ CFStringRef cacheKey;
+ CFDictionaryRef dict;
+ CFArrayRef ifList = NULL;
+ CFIndex count, index;
+ CFStringRef interface;
+ CFStringRef key;
+
+ cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
+ kSCDynamicStoreDomainState);
+
+ dict = cache_SCDynamicStoreCopyValue(store, cacheKey);
+ CFRelease(cacheKey);
+
+ if (dict) {
+ if (isA_CFDictionary(dict)) {
+ /*get a list of the interfaces*/
+ ifList = isA_CFArray(CFDictionaryGetValue(dict, kSCDynamicStorePropNetInterfaces));
+ if (ifList) {
+ count = CFArrayGetCount(ifList);
+
+ /*iterate through list and remove AppleTalk data*/
+ for (index = 0; index < count; index++) {
+ interface = CFArrayGetValueAtIndex(ifList, index);
+ key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+ kSCDynamicStoreDomainState,
+ interface,
+ kSCEntNetAppleTalk);
+ cache_SCDynamicStoreRemoveValue(store, key);
+ CFRelease(key);
+ }
+ }
+ }
+ CFRelease(dict);
+ }
+
+ return;
+}