25 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include <sys/utsname.h>
29 #include <linux/types.h>
36 #include <arpa/inet.h>
37 #include <linux/connector.h>
39 #include <linux/netlink.h>
81 static char kvp_send_buffer[4096];
82 static char kvp_recv_buffer[4096 * 2];
84 static int in_hand_shake = 1;
87 static char *os_major =
"";
88 static char *os_minor =
"";
89 static char *processor_arch;
90 static char *os_build;
92 static struct utsname uts_buf;
98 #define KVP_CONFIG_LOC "/var/opt/"
100 #define MAX_FILE_NAME 100
101 #define ENTRIES_PER_BLOCK 50
118 static void kvp_acquire_lock(
int pool)
123 if (fcntl(kvp_file_info[pool].
fd,
F_SETLKW, &fl) == -1) {
124 syslog(LOG_ERR,
"Failed to acquire the lock pool: %d", pool);
129 static void kvp_release_lock(
int pool)
134 if (fcntl(kvp_file_info[pool].
fd,
F_SETLK, &fl) == -1) {
136 syslog(LOG_ERR,
"Failed to release the lock pool: %d", pool);
141 static void kvp_update_file(
int pool)
144 size_t bytes_written;
150 kvp_acquire_lock(pool);
152 filep = fopen(kvp_file_info[pool].
fname,
"w");
154 kvp_release_lock(pool);
155 syslog(LOG_ERR,
"Failed to open file, pool: %d", pool);
159 bytes_written = fwrite(kvp_file_info[pool].records,
163 if (ferror(filep) || fclose(filep)) {
164 kvp_release_lock(pool);
165 syslog(LOG_ERR,
"Failed to write file, pool: %d", pool);
169 kvp_release_lock(pool);
172 static void kvp_update_mem_state(
int pool)
175 size_t records_read = 0;
178 int num_blocks = kvp_file_info[pool].num_blocks;
181 kvp_acquire_lock(pool);
183 filep = fopen(kvp_file_info[pool].
fname,
"r");
185 kvp_release_lock(pool);
186 syslog(LOG_ERR,
"Failed to open file, pool: %d", pool);
190 readp = &record[records_read];
191 records_read += fread(readp,
sizeof(
struct kvp_record),
192 ENTRIES_PER_BLOCK * num_blocks,
196 syslog(LOG_ERR,
"Failed to read file, pool: %d", pool);
205 record = realloc(record, alloc_unit * num_blocks);
207 if (record ==
NULL) {
208 syslog(LOG_ERR,
"malloc failed");
216 kvp_file_info[pool].num_blocks = num_blocks;
217 kvp_file_info[pool].records =
record;
218 kvp_file_info[pool].num_records = records_read;
221 kvp_release_lock(pool);
223 static int kvp_file_init(
void)
235 if (
access(
"/var/opt/hyperv", F_OK)) {
237 syslog(LOG_ERR,
" Failed to create /var/opt/hyperv");
243 fname = kvp_file_info[
i].fname;
246 sprintf(fname,
"/var/opt/hyperv/.kvp_pool_%d", i);
253 filep = fopen(fname,
"r");
257 record =
malloc(alloc_unit * num_blocks);
258 if (record ==
NULL) {
263 readp = &record[records_read];
264 records_read += fread(readp,
sizeof(
struct kvp_record),
269 syslog(LOG_ERR,
"Failed to read file, pool: %d",
279 record = realloc(record, alloc_unit *
281 if (record ==
NULL) {
289 kvp_file_info[
i].fd =
fd;
290 kvp_file_info[
i].num_blocks = num_blocks;
291 kvp_file_info[
i].records =
record;
292 kvp_file_info[
i].num_records = records_read;
310 kvp_update_mem_state(pool);
312 num_records = kvp_file_info[pool].num_records;
313 record = kvp_file_info[pool].records;
316 if (
memcmp(key, record[i].key, key_size))
322 if (i == num_records) {
323 kvp_file_info[pool].num_records--;
324 kvp_update_file(pool);
331 strcpy(record[j].key, record[k].key);
336 kvp_file_info[pool].num_records--;
337 kvp_update_file(pool);
343 static int kvp_key_add_or_modify(
int pool,
__u8 *key,
int key_size,
__u8 *
value,
358 kvp_update_mem_state(pool);
360 num_records = kvp_file_info[pool].num_records;
361 record = kvp_file_info[pool].records;
362 num_blocks = kvp_file_info[pool].num_blocks;
365 if (
memcmp(key, record[i].key, key_size))
371 memcpy(record[i].value, value, value_size);
372 kvp_update_file(pool);
379 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
381 record = realloc(record,
sizeof(
struct kvp_record) *
382 ENTRIES_PER_BLOCK * (num_blocks + 1));
386 kvp_file_info[pool].num_blocks++;
389 memcpy(record[i].value, value, value_size);
390 memcpy(record[i].key, key, key_size);
391 kvp_file_info[pool].records =
record;
392 kvp_file_info[pool].num_records++;
393 kvp_update_file(pool);
397 static int kvp_get_value(
int pool,
__u8 *key,
int key_size,
__u8 *value,
411 kvp_update_mem_state(pool);
413 num_records = kvp_file_info[pool].num_records;
414 record = kvp_file_info[pool].records;
417 if (
memcmp(key, record[i].key, key_size))
422 memcpy(value, record[i].value, value_size);
429 static int kvp_pool_enumerate(
int pool,
int index,
__u8 *key,
int key_size,
430 __u8 *value,
int value_size)
437 kvp_update_mem_state(pool);
438 record = kvp_file_info[pool].records;
440 if (index >= kvp_file_info[pool].num_records) {
444 memcpy(key, record[index].key, key_size);
445 memcpy(value, record[index].value, value_size);
456 os_build = uts_buf.release;
458 processor_arch = uts_buf.machine;
465 p =
strchr(os_build,
'-');
473 file = fopen(
"/etc/os-release",
"r");
475 while (fgets(buf,
sizeof(buf), file)) {
497 }
else if (*p ==
'\'' || *p ==
'"' ||
506 if (!
strcmp(buf,
"NAME")) {
511 }
else if (!
strcmp(buf,
"VERSION_ID")) {
523 file = fopen(
"/etc/SuSE-release",
"r");
525 goto kvp_osinfo_found;
526 file = fopen(
"/etc/redhat-release",
"r");
528 goto kvp_osinfo_found;
537 p = fgets(buf,
sizeof(buf), file);
548 p = fgets(buf,
sizeof(buf), file);
559 p = fgets(buf,
sizeof(buf), file);
586 static char *kvp_get_if_name(
char *guid)
592 char *if_name =
NULL;
594 char *kvp_net_dir =
"/sys/class/net/";
597 dir = opendir(kvp_net_dir);
601 snprintf(dev_id,
sizeof(dev_id),
"%s", kvp_net_dir);
602 q = dev_id +
strlen(kvp_net_dir);
604 while ((entry = readdir(dir)) !=
NULL) {
609 strcat(dev_id, entry->d_name);
610 strcat(dev_id,
"/device/device_id");
612 file = fopen(dev_id,
"r");
616 p = fgets(buf,
sizeof(buf), file);
627 if_name = strdup(entry->d_name);
643 static char *kvp_if_name_to_mac(
char *if_name)
652 snprintf(addr_file,
sizeof(addr_file),
"%s%s%s",
"/sys/class/net/",
653 if_name,
"/address");
655 file = fopen(addr_file,
"r");
659 p = fgets(buf,
sizeof(buf), file);
664 for (i = 0; i <
strlen(p); i++)
666 mac_addr = strdup(p);
678 static char *kvp_mac_to_if_name(
char *
mac)
684 char *if_name =
NULL;
686 char *kvp_net_dir =
"/sys/class/net/";
690 dir = opendir(kvp_net_dir);
694 snprintf(dev_id,
sizeof(dev_id), kvp_net_dir);
695 q = dev_id +
strlen(kvp_net_dir);
697 while ((entry = readdir(dir)) !=
NULL) {
703 strcat(dev_id, entry->d_name);
704 strcat(dev_id,
"/address");
706 file = fopen(dev_id,
"r");
710 p = fgets(buf,
sizeof(buf), file);
716 for (i = 0; i <
strlen(p); i++)
724 if_name = strdup(entry->d_name);
737 static void kvp_process_ipconfig_file(
char *
cmd,
738 char *config_buf,
int len,
739 int element_size,
int offset)
749 file = popen(cmd,
"r");
754 memset(config_buf, 0, len);
755 while ((p = fgets(buf,
sizeof(buf), file)) !=
NULL) {
756 if ((len -
strlen(config_buf)) < (element_size + 1))
767 static void kvp_get_ipconfig_info(
char *if_name,
778 sprintf(cmd,
"%s %s",
"ip route show dev", if_name);
779 strcat(cmd,
" | awk '/default/ {print $3 }'");
784 kvp_process_ipconfig_file(cmd, (
char *)buffer->
gate_way,
790 sprintf(cmd,
"%s %s",
"ip -f inet6 route show dev", if_name);
791 strcat(cmd,
" | awk '/default/ {print $3 }'");
796 kvp_process_ipconfig_file(cmd, (
char *)buffer->
gate_way,
815 sprintf(cmd,
"%s",
"hv_get_dns_info");
820 kvp_process_ipconfig_file(cmd, (
char *)buffer->
dns_addr,
832 sprintf(cmd,
"%s %s",
"hv_get_dhcp_info", if_name);
834 file = popen(cmd,
"r");
838 p = fgets(dhcp_info,
sizeof(dhcp_info), file);
853 static unsigned int hweight32(
unsigned int *
w)
855 unsigned int res = *w - ((*w >> 1) & 0x55555555);
856 res = (
res & 0x33333333) + ((
res >> 2) & 0x33333333);
859 return (
res + (
res >> 16)) & 0x000000FF;
862 static int kvp_process_ip_address(
void *addrp,
874 str = inet_ntop(family, &addr->
sin_addr, tmp, 50);
878 str = inet_ntop(family, &addr6->
sin6_addr.s6_addr, tmp, 50);
882 if ((length - *offset) < addr_length + 1)
885 strcpy(buffer,
"inet_ntop failed\n");
894 *offset +=
strlen(str) + 1;
899 kvp_get_ip_info(
int family,
char *if_name,
int op,
900 void *out_buffer,
int length)
902 struct ifaddrs *ifap;
903 struct ifaddrs *curp;
919 ip_buffer = out_buffer;
920 buffer = (
char *)ip_buffer->
ip_addr;
928 if (getifaddrs(&ifap)) {
929 strcpy(buffer,
"getifaddrs failed\n");
934 while (curp !=
NULL) {
935 if (curp->ifa_addr ==
NULL) {
936 curp = curp->ifa_next;
940 if ((if_name !=
NULL) &&
946 curp = curp->ifa_next;
956 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
957 curp = curp->ifa_next;
960 if ((curp->ifa_addr->sa_family !=
AF_INET) &&
961 (curp->ifa_addr->sa_family !=
AF_INET6)) {
962 curp = curp->ifa_next;
971 if (curp->ifa_addr->sa_family ==
AF_INET) {
976 error = kvp_process_ip_address(
992 sn_str = (
char *)ip_buffer->
sub_net;
997 for (i = 0; i < 4; i++)
1000 sprintf(cidr_mask,
"/%d", weight);
1001 if ((length - sn_offset) <
1006 strcpy(sn_str, cidr_mask);
1008 strcat(sn_str, cidr_mask);
1010 sn_offset +=
strlen(sn_str) + 1;
1017 kvp_get_ipconfig_info(if_name, ip_buffer);
1021 error = kvp_process_ip_address(curp->ifa_addr,
1022 curp->ifa_addr->sa_family,
1028 curp = curp->ifa_next;
1037 static int expand_ipv6(
char *addr,
int type)
1050 sprintf(addr,
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1051 "%02x%02x:%02x%02x:%02x%02x",
1065 static int is_ipv4(
char *addr)
1070 ret = inet_pton(
AF_INET, addr, &ipv4_addr);
1077 static int parse_ip_val_buffer(
char *in_buf,
int *offset,
1088 start = in_buf + *
offset;
1094 x = start +
strlen(start);
1096 if (
strlen(start) != 0) {
1101 while (start[i] ==
' ')
1104 if ((x - start) <= out_len) {
1105 strcpy(out_buf, (start + i));
1106 *offset += (x -
start) + 1;
1113 static int kvp_write_file(FILE *
f,
char *
s1,
char *
s2,
char *
s3)
1117 ret =
fprintf(f,
"%s%s%s%s\n", s1, s2,
"=", s3);
1126 static int process_ip_string(FILE *f,
char *ip_string,
int type)
1136 memset(addr, 0,
sizeof(addr));
1138 while (parse_ip_val_buffer(ip_string, &offset, addr,
1142 if (is_ipv4(addr)) {
1145 snprintf(str,
sizeof(str),
"%s",
"IPADDR");
1148 snprintf(str,
sizeof(str),
"%s",
"NETMASK");
1151 snprintf(str,
sizeof(str),
"%s",
"GATEWAY");
1154 snprintf(str,
sizeof(str),
"%s",
"DNS");
1165 }
else if (type ==
DNS) {
1166 snprintf(sub_str,
sizeof(sub_str),
"%d", ++i);
1170 }
else if (expand_ipv6(addr, type)) {
1173 snprintf(str,
sizeof(str),
"%s",
"IPV6ADDR");
1176 snprintf(str,
sizeof(str),
"%s",
"IPV6NETMASK");
1183 snprintf(str,
sizeof(str),
"%s",
"DNS");
1186 if ((j != 0) || (type ==
DNS)) {
1194 }
else if (type ==
DNS) {
1202 error = kvp_write_file(f, str, sub_str, addr);
1205 memset(addr, 0,
sizeof(addr));
1266 "hyperv/ifcfg-", if_name);
1268 file = fopen(if_file,
"w");
1271 syslog(LOG_ERR,
"Failed to open config file");
1279 mac_addr = kvp_if_name_to_mac(if_name);
1280 if (mac_addr ==
NULL) {
1285 error = kvp_write_file(file,
"HWADDR",
"", mac_addr);
1289 error = kvp_write_file(file,
"IF_NAME",
"", if_name);
1294 error = kvp_write_file(file,
"DHCP",
"",
"yes");
1309 error = process_ip_string(file, (
char *)new_val->
ip_addr,
IPADDR);
1313 error = process_ip_string(file, (
char *)new_val->
sub_net,
NETMASK);
1321 error = process_ip_string(file, (
char *)new_val->
dns_addr,
DNS);
1334 snprintf(cmd,
sizeof(cmd),
"%s %s",
"hv_set_ifconfig", if_file);
1339 syslog(LOG_ERR,
"Failed to write config file");
1347 kvp_get_domain_name(
char *buffer,
int length)
1349 struct addrinfo hints, *
info ;
1352 gethostname(buffer, length);
1353 memset(&hints, 0,
sizeof(hints));
1356 hints.ai_flags = AI_CANONNAME;
1358 error = getaddrinfo(buffer,
NULL, &hints, &info);
1360 strcpy(buffer,
"getaddrinfo failed\n");
1363 strcpy(buffer, info->ai_canonname);
1375 struct iovec iov[2];
1386 iov[0].iov_base = nlh;
1387 iov[0].iov_len =
sizeof(*nlh);
1389 iov[1].iov_base =
msg;
1390 iov[1].iov_len =
size;
1398 return sendmsg(fd, &
message, 0);
1403 int fd, len, sock_opt;
1408 struct cn_msg *incoming_cn_msg;
1419 openlog(
"KVP", 0, LOG_USER);
1420 syslog(LOG_INFO,
"KVP starting; pid is:%d", getpid());
1426 if (kvp_file_init()) {
1427 syslog(LOG_ERR,
"Failed to initialize the pools");
1433 syslog(LOG_ERR,
"netlink socket creation failed; error:%d", fd);
1442 error = bind(fd, (
struct sockaddr *)&addr,
sizeof(addr));
1444 syslog(LOG_ERR,
"bind failed; error:%d", error);
1448 sock_opt = addr.nl_groups;
1449 setsockopt(fd, 270, 1, &sock_opt,
sizeof(sock_opt));
1453 message = (
struct cn_msg *)kvp_send_buffer;
1464 syslog(LOG_ERR,
"netlink_send failed; error:%d", len);
1473 socklen_t addr_l =
sizeof(
addr);
1478 len = recvfrom(fd, kvp_recv_buffer,
sizeof(kvp_recv_buffer), 0,
1481 if (len < 0 || addr.nl_pid) {
1482 syslog(LOG_ERR,
"recvfrom failed; pid:%u error:%d %s",
1488 incoming_msg = (
struct nlmsghdr *)kvp_recv_buffer;
1497 op = hv_msg->
kvp_hdr.operation;
1511 syslog(LOG_INFO,
"KVP LIC Version: %s",
1514 syslog(LOG_ERR,
"malloc failed");
1523 kvp_mac_to_if_name((
char *)kvp_ip_val->
adapter_id);
1525 if (if_name ==
NULL) {
1533 error = kvp_get_ip_info(
1546 if_name = kvp_get_if_name(
1548 if (if_name ==
NULL) {
1556 error = kvp_set_ip_info(if_name, kvp_ip_val);
1564 if (kvp_key_add_or_modify(pool,
1573 if (kvp_get_value(pool,
1582 if (kvp_key_delete(pool,
1601 if (kvp_pool_enumerate(pool,
1617 kvp_get_domain_name(key_value,
1619 strcpy(key_name,
"FullyQualifiedDomainName");
1622 strcpy(key_name,
"IntegrationServicesVersion");
1628 strcpy(key_name,
"NetworkAddressIPv4");
1633 strcpy(key_name,
"NetworkAddressIPv6");
1636 strcpy(key_value, os_build);
1637 strcpy(key_name,
"OSBuildNumber");
1641 strcpy(key_name,
"OSName");
1644 strcpy(key_value, os_major);
1645 strcpy(key_name,
"OSMajorVersion");
1648 strcpy(key_value, os_minor);
1649 strcpy(key_name,
"OSMinorVersion");
1652 strcpy(key_value, os_build);
1653 strcpy(key_name,
"OSVersion");
1656 strcpy(key_value, processor_arch);
1657 strcpy(key_name,
"ProcessorArchitecture");
1672 incoming_cn_msg->
ack = 0;
1677 syslog(LOG_ERR,
"net_link send failed; error:%d", len);