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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <strings.h> 29 #include <stropts.h> 30 #include <unistd.h> 31 #include <uuid/uuid.h> 32 #include <sys/sockio.h> 33 #include <libdlpi.h> 34 #include <sys/utsname.h> 35 36 #include <netdb.h> 37 #include <netinet/in.h> 38 #include <arpa/inet.h> 39 40 #include "etheraddr.h" 41 42 static boolean_t get_etheraddr(const char *linkname, void *arg); 43 44 /* 45 * get an individual arp entry 46 */ 47 int 48 arp_get(uuid_node_t *node) 49 { 50 struct utsname name; 51 struct arpreq ar; 52 struct hostent *hp; 53 struct sockaddr_in *sin; 54 int s; 55 56 if (uname(&name) == -1) { 57 return (-1); 58 } 59 (void) memset(&ar, 0, sizeof (ar)); 60 ar.arp_pa.sa_family = AF_INET; 61 /* LINTED pointer */ 62 sin = (struct sockaddr_in *)&ar.arp_pa; 63 sin->sin_family = AF_INET; 64 sin->sin_addr.s_addr = inet_addr(name.nodename); 65 if (sin->sin_addr.s_addr == (in_addr_t)-1) { 66 hp = gethostbyname(name.nodename); 67 if (hp == NULL) { 68 return (-1); 69 } 70 (void) memcpy(&sin->sin_addr, hp->h_addr, 71 sizeof (sin->sin_addr)); 72 } 73 s = socket(AF_INET, SOCK_DGRAM, 0); 74 if (s < 0) { 75 return (-1); 76 } 77 if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) { 78 (void) close(s); 79 return (-1); 80 } 81 (void) close(s); 82 if (ar.arp_flags & ATF_COM) { 83 bcopy(&ar.arp_ha.sa_data, node, 6); 84 } else 85 return (-1); 86 return (0); 87 } 88 89 /* 90 * Name: get_ethernet_address 91 * 92 * Description: Obtains the system ethernet address. 93 * 94 * Returns: 0 on success, non-zero otherwise. The system ethernet 95 * address is copied into the passed-in variable. 96 */ 97 int 98 get_ethernet_address(uuid_node_t *node) 99 { 100 walker_arg_t state; 101 102 if (arp_get(node) == 0) 103 return (0); 104 105 /* 106 * Try to get physical (ethernet) address from network interfaces. 107 */ 108 state.wa_addrvalid = B_FALSE; 109 dlpi_walk(get_etheraddr, &state, 0); 110 if (state.wa_addrvalid) 111 bcopy(state.wa_etheraddr, node, state.wa_etheraddrlen); 112 113 return (state.wa_addrvalid ? 0 : -1); 114 } 115 116 /* 117 * Get the physical address via DLPI and update the flag to true upon success. 118 */ 119 static boolean_t 120 get_etheraddr(const char *linkname, void *arg) 121 { 122 int retval; 123 dlpi_handle_t dh; 124 walker_arg_t *statep = arg; 125 126 if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS) 127 return (B_FALSE); 128 129 statep->wa_etheraddrlen = DLPI_PHYSADDR_MAX; 130 retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, 131 statep->wa_etheraddr, &(statep->wa_etheraddrlen)); 132 133 dlpi_close(dh); 134 135 if (retval == DLPI_SUCCESS) { 136 statep->wa_addrvalid = B_TRUE; 137 return (B_TRUE); 138 } 139 return (B_FALSE); 140 } 141