1/* 2 * Copyright (c) 2001-2002, 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 * 23 */ 24 25/* 26 * LinkAddresses.c 27 * - get the list of link-level addresses 28 */ 29/* 30 * Modification History 31 * 32 * November 1, 2001 Dieter Siegmund (dieter@apple.com) 33 * - created 34 */ 35 36#include <stdio.h> 37#include <unistd.h> 38#include <stdlib.h> 39#include <sys/types.h> 40#include <sys/ioctl.h> 41#include <sys/sysctl.h> 42#include <sys/socket.h> 43#include <sys/filio.h> 44#include <errno.h> 45#include <net/if.h> 46#include <net/if_dl.h> 47#include <net/if_media.h> 48#include <net/route.h> 49#include <string.h> 50 51#include "LinkAddresses.h" 52 53struct LinkAddresses_s { 54 struct sockaddr_dl * * list; 55 int count; 56}; 57 58void 59sockaddr_dl_print(struct sockaddr_dl * dl_p) 60{ 61 int i; 62 63 printf("link: len %d index %d family %d type 0x%x nlen %d alen %d" 64 " slen %d addr ", dl_p->sdl_len, 65 dl_p->sdl_index, dl_p->sdl_family, dl_p->sdl_type, 66 dl_p->sdl_nlen, dl_p->sdl_alen, dl_p->sdl_slen); 67 for (i = 0; i < dl_p->sdl_alen; i++) 68 printf("%s%x", i ? ":" : "", 69 ((unsigned char *)dl_p->sdl_data + dl_p->sdl_nlen)[i]); 70 printf("\n"); 71} 72 73#ifdef TEST_LINKADDRESSES 74static void 75LinkAddresses_print(LinkAddressesRef link_addrs) 76{ 77 int i; 78 for (i = 0; i < link_addrs->count; i++) { 79 struct sockaddr_dl * sdl = link_addrs->list[i]; 80 printf("%.*s ", sdl->sdl_nlen, sdl->sdl_data); 81 sockaddr_dl_print(sdl); 82 } 83} 84#endif /* TEST_LINKADDRESSES */ 85 86struct sockaddr_dl * 87LinkAddresses_lookup(LinkAddressesRef list, char * ifname) 88{ 89 int i; 90 int len = (int)strlen(ifname); 91 92 for (i = 0; i < list->count; i++) { 93 struct sockaddr_dl * sdl = list->list[i]; 94 95 if (strncmp(sdl->sdl_data, ifname, sdl->sdl_nlen) == 0 96 && len == sdl->sdl_nlen) { 97 return (sdl); 98 } 99 } 100 return (NULL); 101} 102 103int 104LinkAddresses_count(LinkAddressesRef list) 105{ 106 return (list->count); 107} 108 109struct sockaddr_dl * 110LinkAddresses_element(LinkAddressesRef list, int i) 111{ 112 if (i >= 0 && i < list->count) { 113 return (list->list[i]); 114 } 115 return (NULL); 116} 117 118void 119LinkAddresses_free(LinkAddressesRef * list_p) 120{ 121 int i; 122 LinkAddressesRef list = *list_p; 123 124 if (list) { 125 for (i = 0; i < list->count; i++) { 126 free(list->list[i]); 127 list->list[i] = NULL; 128 } 129 free(list->list); 130 list->list = NULL; 131 list->count = 0; 132 free(list); 133 } 134 *list_p = NULL; 135 return; 136} 137 138LinkAddressesRef 139LinkAddresses_create() 140{ 141 char * buf = NULL; 142 size_t buf_len = 0; 143 int mib[6]; 144 int offset = 0; 145 struct sockaddr_dl * * list = NULL; 146 int list_size = 10; 147 int list_count = 0; 148 LinkAddressesRef ret_list = NULL; 149 150 mib[0] = CTL_NET; 151 mib[1] = PF_ROUTE; 152 mib[2] = 0; 153 mib[3] = AF_LINK; 154 mib[4] = NET_RT_IFLIST; 155 mib[5] = 0; 156 157 if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) < 0) { 158 fprintf(stderr, "sysctl() size failed: %s", strerror(errno)); 159 goto failed; 160 } 161 buf = malloc(buf_len); 162 if (sysctl(mib, 6, buf, &buf_len, NULL, 0) < 0) { 163 fprintf(stderr, "sysctl() failed: %s", strerror(errno)); 164 goto failed; 165 } 166 list = (struct sockaddr_dl * *)malloc(sizeof(*list) * list_size); 167 if (list == NULL) { 168 goto failed; 169 } 170 offset = 0; 171 while (offset < buf_len) { 172 struct if_msghdr * ifm; 173 struct sockaddr_dl * sdl; 174 struct sockaddr_dl * new_p; 175 176 /* ALIGN: buf is aligned to at least sizeof(int) bytes */ 177 ifm = (struct if_msghdr *)(void *)&buf[offset]; 178 179 switch (ifm->ifm_type) { 180 case RTM_IFINFO: 181 /* get interface name */ 182 sdl = (struct sockaddr_dl *)(ifm + 1); 183 if (list_count == list_size) { 184 list_size *= 2; 185 list = realloc(list, sizeof(*list) * list_size); 186 if (list == NULL) { 187 goto failed; 188 } 189 } 190 new_p = (void *)malloc(sdl->sdl_len); 191 if (new_p == NULL) { 192 break; 193 } 194 bcopy(sdl, new_p, sdl->sdl_len); 195 list[list_count++] = new_p; 196 break; 197 198 default: 199 break; 200 } 201 /* advance to next address/interface */ 202 offset += ifm->ifm_msglen; 203 } 204 if (list_count == 0) { 205 free(list); 206 list = NULL; 207 } 208 else if (list_count < list_size) { 209 list = reallocf(list, sizeof(*list) * list_count); 210 } 211 if (list != NULL) { 212 ret_list = (void *)malloc(sizeof(*ret_list)); 213 if (ret_list) { 214 ret_list->list = list; 215 ret_list->count = list_count; 216 } 217 else { 218 free(list); 219 list = NULL; 220 } 221 } 222 failed: 223 if (buf != NULL) { 224 free(buf); 225 } 226 return (ret_list); 227} 228 229#ifdef TEST_LINKADDRESSES 230int 231main() 232{ 233 LinkAddressesRef link_addrs; 234 235 link_addrs = LinkAddresses_create(); 236 if (link_addrs) { 237 LinkAddresses_print(link_addrs); 238 LinkAddresses_free(&link_addrs); 239 } 240 exit(0); 241} 242#endif /* TEST_LINKADDRESSES */ 243