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 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 26 */ 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 <sys/utsname.h> 36 37 #include <netdb.h> 38 #include <netinet/in.h> 39 #include <arpa/inet.h> 40 41 #include "etheraddr.h" 42 43 /* 44 * get an individual arp entry 45 */ 46 static int 47 arp_get(uuid_node_t *node) 48 { 49 struct utsname name; 50 struct arpreq ar; 51 struct hostent *hp; 52 struct sockaddr_in *sin; 53 int s; 54 55 if (uname(&name) == -1) { 56 return (-1); 57 } 58 (void) memset(&ar, 0, sizeof (ar)); 59 ar.arp_pa.sa_family = AF_INET; 60 /* LINTED pointer */ 61 sin = (struct sockaddr_in *)&ar.arp_pa; 62 sin->sin_family = AF_INET; 63 sin->sin_addr.s_addr = inet_addr(name.nodename); 64 if (sin->sin_addr.s_addr == (in_addr_t)-1) { 65 hp = gethostbyname(name.nodename); 66 if (hp == NULL) { 67 return (-1); 68 } 69 (void) memcpy(&sin->sin_addr, hp->h_addr, 70 sizeof (sin->sin_addr)); 71 } 72 s = socket(AF_INET, SOCK_DGRAM, 0); 73 if (s < 0) { 74 return (-1); 75 } 76 if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) { 77 (void) close(s); 78 return (-1); 79 } 80 (void) close(s); 81 if (ar.arp_flags & ATF_COM) { 82 bcopy(&ar.arp_ha.sa_data, node, 6); 83 } else 84 return (-1); 85 return (0); 86 } 87 88 /* 89 * Fake up a valid Ethernet address based on gethostid(). 90 * This is likely to be unique to this machine, and that's 91 * good enough for libuuid when we can't easily get our 92 * real Ethernet address. 93 */ 94 static int 95 hostid_get(uuid_node_t *node) 96 { 97 uint32_t hostid; 98 99 if ((hostid = (uint32_t)gethostid()) == 0) 100 return (-1); 101 hostid = htonl(hostid); 102 103 /* 104 * Like gen_ethernet_address(), use prefix: 105 * 8:0:... with the multicast bit set. 106 */ 107 node->nodeID[0] = 0x88; 108 node->nodeID[1] = 0x00; 109 (void) memcpy(node->nodeID + 2, &hostid, sizeof (hostid)); 110 111 return (0); 112 } 113 114 /* 115 * Name: get_ethernet_address 116 * 117 * Description: Obtains the system ethernet address, if possible. 118 * 119 * Returns: 0 on success, non-zero otherwise. The system ethernet 120 * address is copied into the passed-in variable. 121 * 122 * Note: This does NOT need to get the REAL Ethernet address. 123 * This library only needs something that looks like an Ethernet 124 * address and that's likely to be unique to this machine. Also, 125 * we really don't want to drag in libdlpi (etc) here so this just 126 * tries an SIOCGARP ioctl, then a hostid-derived method. If all 127 * methods here fail, the caller generates an Ethernet address. 128 */ 129 int 130 get_ethernet_address(uuid_node_t *node) 131 { 132 133 if (arp_get(node) == 0) 134 return (0); 135 136 if (hostid_get(node) == 0) 137 return (0); 138 139 return (-1); 140 }