1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdlib.h> 29 #include <stdio.h> 30 #include <strings.h> 31 #include <stropts.h> 32 #include <unistd.h> 33 #include <uuid/uuid.h> 34 #include <sys/sockio.h> 35 #include <libdlpi.h> 36 #include <libdllink.h> 37 #include <sys/utsname.h> 38 39 #include <netdb.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 43 #include "etheraddr.h" 44 45 /* 46 * debugging flag 47 */ 48 static int debug = 0; 49 50 static void get_etheraddr(void *arg, const char *linkname); 51 52 /* 53 * get an individual arp entry 54 */ 55 int 56 arp_get(uuid_node_t *node) 57 { 58 struct utsname name; 59 struct arpreq ar; 60 struct hostent *hp; 61 struct sockaddr_in *sin; 62 int s; 63 64 if (uname(&name) == -1) { 65 return (-1); 66 } 67 (void) memset(&ar, 0, sizeof (ar)); 68 ar.arp_pa.sa_family = AF_INET; 69 /* LINTED pointer */ 70 sin = (struct sockaddr_in *)&ar.arp_pa; 71 sin->sin_family = AF_INET; 72 sin->sin_addr.s_addr = inet_addr(name.nodename); 73 if (sin->sin_addr.s_addr == (in_addr_t)-1) { 74 hp = gethostbyname(name.nodename); 75 if (hp == NULL) { 76 return (-1); 77 } 78 (void) memcpy(&sin->sin_addr, hp->h_addr, 79 sizeof (sin->sin_addr)); 80 } 81 s = socket(AF_INET, SOCK_DGRAM, 0); 82 if (s < 0) { 83 return (-1); 84 } 85 if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) { 86 (void) close(s); 87 return (-1); 88 } 89 (void) close(s); 90 if (ar.arp_flags & ATF_COM) { 91 bcopy(&ar.arp_ha.sa_data, node, 6); 92 } else 93 return (-1); 94 return (0); 95 } 96 97 /* 98 * Name: get_ethernet_address 99 * 100 * Description: Obtains the system ethernet address. 101 * 102 * Returns: 0 on success, non-zero otherwise. The system ethernet 103 * address is copied into the passed-in variable. 104 */ 105 int 106 get_ethernet_address(uuid_node_t *node) 107 { 108 walker_arg_t state; 109 110 if (arp_get(node) == 0) 111 return (0); 112 113 /* 114 * Try to get physical (ethernet) address from network interfaces. 115 */ 116 state.wa_addrvalid = B_FALSE; 117 if (dladm_walk(get_etheraddr, &state) == 0 && state.wa_addrvalid) { 118 bcopy(state.wa_etheraddr, node, state.wa_etheraddrlen); 119 } 120 121 return (state.wa_addrvalid ? 0 : -1); 122 } 123 124 /* 125 * Get the physical address via dlpi and update the flag to true upon success. 126 */ 127 static void 128 get_etheraddr(void *arg, const char *linkname) 129 { 130 int retval; 131 dlpi_handle_t dh; 132 walker_arg_t *statep = arg; 133 134 if (!(statep->wa_addrvalid)) { 135 if (debug) 136 (void) printf("get_etheraddr: opening %s\n", linkname); 137 if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) { 138 if (debug) { 139 (void) fprintf(stderr, "get_etheraddr: " 140 "cannot open link: \"%s\" %s\n", 141 linkname, retval); 142 } 143 return; 144 } 145 146 if (debug) { 147 (void) printf("get_etheraddr: getting ethernet address" 148 " from link: %s\n", linkname); 149 } 150 statep->wa_etheraddrlen = DLPI_PHYSADDR_MAX; 151 retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, 152 statep->wa_etheraddr, &(statep->wa_etheraddrlen)); 153 if (debug) { 154 (void) fprintf(stderr, "get_etheraddr: " 155 "dlpi_get_physaddr: \"%s\" %s\n", linkname, retval); 156 } 157 158 if (retval == DLPI_SUCCESS) 159 statep->wa_addrvalid = B_TRUE; 160 161 dlpi_close(dh); 162 } 163 } 164