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