static NetlinkList *getResultList(int p_socket, int p_request) { if(netlink_send(p_socket, p_request) < 0) { return NULL; } NetlinkList *l_list = NULL; NetlinkList *l_end = NULL; int l_size; int l_done = 0; while(!l_done) { struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); if(!l_hdr) { // error freeResultList(l_list); return NULL; } NetlinkList *l_item = newListItem(l_hdr, l_size); if(!l_list) { l_list = l_item; } else { l_end->m_next = l_item; } l_end = l_item; } return l_list; }
static void test_nfacct_del(struct netlink_info *netlink, const char *name) { struct nfgenmsg *hdr; size_t len, name_len; name_len = strlen(name) + 1; len = NLMSG_ALIGN(sizeof(struct nfgenmsg)) + NLA_ALIGN(sizeof(struct nlattr)) + name_len; hdr = g_malloc0(len); hdr->nfgen_family = AF_UNSPEC; hdr->version = NFNETLINK_V0; hdr->res_id = 0; append_attr_str(NLA_DATA(hdr), NFACCT_NAME, name_len, name); netlink_send(netlink, NFNL_SUBSYS_ACCT << 8 | NFNL_MSG_ACCT_DEL, NLM_F_ACK, hdr, len, test_nfacct_callback, NULL, NULL); g_free(hdr); }
int netlink_sendto(void *sock, void *data, int size, unsigned int flags, struct sockaddr *to, socklen_t tolen) { /*printf("netlink_sendto\n");*/ netlink_send(sock,data,size,flags); return 0; }
void *tx_thread(void *arg) { int fd=*((int*)arg); RT_TASK *task; int ret; int i; char dummy_data[10]; if (fd > 0) { ret = netlink_send(fd,NLCMD_INIT,10,&dummy_data[0]); printf("tx_thread starting, fd %d\n",fd); task = rt_task_init_schmod(nam2num("TASK1"), 0, 0, 0, SCHED_FIFO, 0xF); mlockall(MCL_CURRENT | MCL_FUTURE); // rt_make_hard_real_time(); while (!oai_exit) { if (tx_sdu_active == 1) printf("tx_thread: waiting (MBOX %d)\n",((unsigned int*)DAQ_MBOX)[0]); while(((volatile int)tx_sdu_active) != 0) { rt_sleep(nano2count(66666)); } printf("tx_thread: calling netlink\n"); ret = netlink_recv(fd,rxsdu); tx_sdu_active = 1; tx_sdu_length = ret; /* if (ret > 0) { printf("received TX SDU: "); for (i=0;i<ret;i++) { printf("%02hhx ",rxsdu[i]); } printf("\n"); } */ } } else { printf("tx_thread: no netlink\n"); } printf("tx_thread exiting\n"); return(0); }
void netlink_receive(struct sk_buff *skb) { struct nlmsghdr *nlh; nlh = (struct nlmsghdr *)skb->data; printk(KERN_ALERT "%s\n",(char *)NLMSG_DATA(nlh)); /* userspace app pid */ nlk_pid = NETLINK_CB(skb).pid; printk(KERN_ALERT "nlk_pid: %d\n", nlk_pid); netlink_send(); }
/* ksend_thread starts after calling kthread_run in * netlink_receive * * ksend_thread: init the wait queue * sets the current task as INTERRUPTIBLE (ready to sleep) * adds the current task to the wait queue * if nlk_pid == 0 ksend_thread goes to sleep calling schedule() * else sets the current task as RUNNING and dequeues it * from the wait queue * calls netlink_send() * * netlink_receive() after setting nlk_pid wakes ksend_thread * calling wake_up_interruptible */ static int ksend_thread(void *dummy) { DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&ksend_wait, &wait); if(!nlk_pid){ schedule(); } __set_current_state(TASK_RUNNING); remove_wait_queue(&ksend_wait, &wait); netlink_send(); return 0; }
static void test_nfacct_dump(struct netlink_info *netlink) { struct nfgenmsg hdr; memset(&hdr, 0, sizeof(hdr)); hdr.nfgen_family = AF_UNSPEC; hdr.version = NFNETLINK_V0; hdr.res_id = 0; netlink_send(netlink, NFNL_SUBSYS_ACCT << 8 | NFNL_MSG_ACCT_GET, NLM_F_DUMP , &hdr, sizeof(hdr), test_nfacct_dump_callback, NULL, NULL); }
int req_exec(int s, struct cn_msg *msg) { struct uvesafb_task *tsk = (struct uvesafb_task*)(msg + 1); u8 *buf = (u8*)tsk + sizeof(struct uvesafb_task); if (tsk->flags & TF_EXIT) return 1; if (v86_task(tsk, buf)) return 2; netlink_send(s, msg); return 0; }
int main(int argc, char* argv[]) { int fd; if (argc == 2) { filefd = open(argv[1], O_WRONLY|O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); if (filefd < 0) { printf("open file %s: %s", argv[1], strerror(errno)); return -1; } } else{ filefd = 1; } fd = netlink_bind(NETLINK_TCP_RECORD); if(fd == -1){ printf("error getting socket: %s", strerror(errno)); return -1; } int rc; rc = netlink_send(fd, "hi", 100); if (rc < 0) { printf("get error sendmsg = %s\n",strerror(errno)); return -1; } printf("waiting received!\n"); netlink_recv(fd, msg_handler); close(fd); return 0; }
static void test_case_1(void) { struct netlink_info *netlink; struct ifinfomsg msg; netlink = netlink_new(NETLINK_ROUTE); printf("\n"); netlink_set_debug(netlink, do_debug, "[NETLINK] ", NULL); memset(&msg, 0, sizeof(msg)); netlink_send(netlink, RTM_GETLINK, NLM_F_DUMP, &msg, sizeof(msg), getlink_callback, NULL, NULL); mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(mainloop); g_main_loop_unref(mainloop); netlink_destroy(netlink); }
static int netlink_send_dump_request(int type, unsigned char family) { char buffer[sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg) + 16]; struct nlmsghdr *message_header = (void*)buffer; struct rtgenmsg *message = NULL; memset(buffer, 0, sizeof(buffer)); /* Set the header */ message_header->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; message_header->nlmsg_type = type; message_header->nlmsg_len = NLMSG_LENGTH(0); /* Append the message */ message = NLMSG_DATA(message_header); message->rtgen_family = family; message_header->nlmsg_len += NLMSG_ALIGN(sizeof(struct rtgenmsg)); assert(message_header->nlmsg_len <= sizeof(buffer)); return netlink_send(message_header, nl_socket); }
int netlink_send_nlh( struct proxy_dev *pdev, struct nlmsghdr *nlh) { struct nlmsgerr *msgerr = NULL; int rvalue = -1; nlh->nlmsg_pid = pdev->pid; /* send everything */ if (netlink_send(pdev, nlh) == -1) { printf("netlink_send_nlh: failed to send message\n"); return -1; /* failure */ } /* get confirmation of delivery */ if ((nlh = netlink_recv(pdev)) == NULL) { printf("netlink_send_nlh: failed to receive confirmation\n"); return -1; /* failure */ } /* check confirmation */ if ( nlh->nlmsg_type == NLMSG_ERROR ) { msgerr = ((struct nlmsgerr*)NLMSG_DATA(nlh)); if (msgerr->error != 0) { debug("delivery failure, msgerr->error = %d", msgerr->error); goto err; } } else { printf("netlink_send: next message was not confirmation!\n"); goto err; } rvalue = 0; /* success */ err: free(nlh); return rvalue; }
extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer) { int ret; struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = answer, .iov_len = answer->nlmsghdr.nlmsg_len, }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; again: ret = recvmsg(handler->fd, &msg, 0); if (ret < 0) { if (errno == EINTR) goto again; return -errno; } if (!ret) return 0; if (msg.msg_flags & MSG_TRUNC) return -EMSGSIZE; return ret; } extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg) { struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*)nlmsg, .iov_len = nlmsg->nlmsghdr.nlmsg_len, }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int ret; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; ret = sendmsg(handler->fd, &msg, 0); if (ret < 0) { return -errno; } return ret; } #ifndef NLMSG_ERROR #define NLMSG_ERROR 0x2 #endif extern int netlink_transaction(struct nl_handler *handler, struct nlmsg *request, struct nlmsg *answer) { int ret; ret = netlink_send(handler, request); if (ret < 0) return ret; ret = netlink_rcv(handler, answer); if (ret < 0) return ret; if (answer->nlmsghdr.nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(answer); errno = -err->error; if (errno) perror("Error configuring kernel"); return -errno; } return 0; } extern int netlink_open(struct nl_handler *handler, int protocol) { socklen_t socklen; int sndbuf = 32768; int rcvbuf = 32768; memset(handler, 0, sizeof(*handler)); handler->fd = socket(AF_NETLINK, SOCK_RAW, protocol); if (handler->fd < 0) return -errno; if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) return -errno; if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,sizeof(rcvbuf)) < 0) return -errno; memset(&handler->local, 0, sizeof(handler->local)); handler->local.nl_family = AF_NETLINK; handler->local.nl_groups = 0; if (bind(handler->fd, (struct sockaddr*)&handler->local, sizeof(handler->local)) < 0) return -errno; socklen = sizeof(handler->local); if (getsockname(handler->fd, (struct sockaddr*)&handler->local, &socklen) < 0) return -errno; if (socklen != sizeof(handler->local)) return -EINVAL; if (handler->local.nl_family != AF_NETLINK) return -EINVAL; handler->seq = time(NULL); return 0; } extern int netlink_close(struct nl_handler *handler) { close(handler->fd); handler->fd = -1; return 0; }
extern int rtnetlink_send(struct rtnl_handler *handler, struct rtnlmsg *rtnlmsg) { return netlink_send(&handler->nlh, (struct nlmsg *)&rtnlmsg->nlmsghdr); }
int main(void) { int fd, len, sock_opt; int error; struct cn_msg *message; struct pollfd pfd; struct nlmsghdr *incoming_msg; struct cn_msg *incoming_cn_msg; struct hv_ku_msg *hv_msg; char *p; char *key_value; char *key_name; daemon(1, 0); openlog("KVP", 0, LOG_USER); syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); /* * Retrieve OS release information. */ kvp_get_os_info(); fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (fd < 0) { syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); exit(-1); } addr.nl_family = AF_NETLINK; addr.nl_pad = 0; addr.nl_pid = 0; addr.nl_groups = CN_KVP_IDX; error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); if (error < 0) { syslog(LOG_ERR, "bind failed; error:%d", error); close(fd); exit(-1); } sock_opt = addr.nl_groups; setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt)); /* * Register ourselves with the kernel. */ message = (struct cn_msg *)kvp_send_buffer; message->id.idx = CN_KVP_IDX; message->id.val = CN_KVP_VAL; message->seq = KVP_REGISTER; message->ack = 0; message->len = 0; len = netlink_send(fd, message); if (len < 0) { syslog(LOG_ERR, "netlink_send failed; error:%d", len); close(fd); exit(-1); } pfd.fd = fd; while (1) { struct sockaddr *addr_p = (struct sockaddr *) &addr; socklen_t addr_l = sizeof(addr); pfd.events = POLLIN; pfd.revents = 0; poll(&pfd, 1, -1); len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0, addr_p, &addr_l); if (len < 0 || addr.nl_pid) { syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", addr.nl_pid, errno, strerror(errno)); close(fd); return -1; } incoming_msg = (struct nlmsghdr *)kvp_recv_buffer; incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); switch (incoming_cn_msg->seq) { case KVP_REGISTER: /* * Driver is registering with us; stash away the version * information. */ p = (char *)incoming_cn_msg->data; lic_version = malloc(strlen(p) + 1); if (lic_version) { strcpy(lic_version, p); syslog(LOG_INFO, "KVP LIC Version: %s", lic_version); } else { syslog(LOG_ERR, "malloc failed"); } continue; case KVP_KERNEL_GET: break; default: continue; } hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data; key_name = (char *)hv_msg->kvp_key; key_value = (char *)hv_msg->kvp_value; switch (hv_msg->kvp_index) { case FullyQualifiedDomainName: kvp_get_domain_name(key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "FullyQualifiedDomainName"); break; case IntegrationServicesVersion: strcpy(key_name, "IntegrationServicesVersion"); strcpy(key_value, lic_version); break; case NetworkAddressIPv4: kvp_get_ip_address(AF_INET, key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "NetworkAddressIPv4"); break; case NetworkAddressIPv6: kvp_get_ip_address(AF_INET6, key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "NetworkAddressIPv6"); break; case OSBuildNumber: strcpy(key_value, os_build); strcpy(key_name, "OSBuildNumber"); break; case OSName: strcpy(key_value, os_name); strcpy(key_name, "OSName"); break; case OSMajorVersion: strcpy(key_value, os_major); strcpy(key_name, "OSMajorVersion"); break; case OSMinorVersion: strcpy(key_value, os_minor); strcpy(key_name, "OSMinorVersion"); break; case OSVersion: strcpy(key_value, os_build); strcpy(key_name, "OSVersion"); break; case ProcessorArchitecture: strcpy(key_value, processor_arch); strcpy(key_name, "ProcessorArchitecture"); break; default: strcpy(key_value, "Unknown Key"); /* * We use a null key name to terminate enumeration. */ strcpy(key_name, ""); break; } /* * Send the value back to the kernel. The response is * already in the receive buffer. Update the cn_msg header to * reflect the key value that has been added to the message */ incoming_cn_msg->id.idx = CN_KVP_IDX; incoming_cn_msg->id.val = CN_KVP_VAL; incoming_cn_msg->seq = KVP_USER_SET; incoming_cn_msg->ack = 0; incoming_cn_msg->len = sizeof(struct hv_ku_msg); len = netlink_send(fd, incoming_cn_msg); if (len < 0) { syslog(LOG_ERR, "net_link send failed; error:%d", len); exit(-1); } } }
int main(void) { int fd, len, sock_opt; int error; struct cn_msg *message; struct pollfd pfd; struct nlmsghdr *incoming_msg; struct cn_msg *incoming_cn_msg; struct hv_kvp_msg *hv_msg; char *p; char *key_value; char *key_name; daemon(1, 0); openlog("KVP", 0, LOG_USER); syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); kvp_get_os_info(); if (kvp_file_init()) { syslog(LOG_ERR, "Failed to initialize the pools"); exit(EXIT_FAILURE); } fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (fd < 0) { syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); exit(EXIT_FAILURE); } addr.nl_family = AF_NETLINK; addr.nl_pad = 0; addr.nl_pid = 0; addr.nl_groups = CN_KVP_IDX; error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); if (error < 0) { syslog(LOG_ERR, "bind failed; error:%d", error); close(fd); exit(EXIT_FAILURE); } sock_opt = addr.nl_groups; setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt)); message = (struct cn_msg *)kvp_send_buffer; message->id.idx = CN_KVP_IDX; message->id.val = CN_KVP_VAL; hv_msg = (struct hv_kvp_msg *)message->data; hv_msg->kvp_hdr.operation = KVP_OP_REGISTER; message->ack = 0; message->len = sizeof(struct hv_kvp_msg); len = netlink_send(fd, message); if (len < 0) { syslog(LOG_ERR, "netlink_send failed; error:%d", len); close(fd); exit(EXIT_FAILURE); } pfd.fd = fd; while (1) { struct sockaddr *addr_p = (struct sockaddr *) &addr; socklen_t addr_l = sizeof(addr); pfd.events = POLLIN; pfd.revents = 0; poll(&pfd, 1, -1); len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0, addr_p, &addr_l); if (len < 0 || addr.nl_pid) { syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", addr.nl_pid, errno, strerror(errno)); close(fd); return -1; } incoming_msg = (struct nlmsghdr *)kvp_recv_buffer; incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; switch (hv_msg->kvp_hdr.operation) { case KVP_OP_REGISTER: p = (char *)hv_msg->body.kvp_register.version; lic_version = malloc(strlen(p) + 1); if (lic_version) { strcpy(lic_version, p); syslog(LOG_INFO, "KVP LIC Version: %s", lic_version); } else { syslog(LOG_ERR, "malloc failed"); } continue; case KVP_OP_SET: if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool, hv_msg->body.kvp_set.data.key, hv_msg->body.kvp_set.data.key_size, hv_msg->body.kvp_set.data.value, hv_msg->body.kvp_set.data.value_size)) strcpy(hv_msg->body.kvp_set.data.key, ""); break; case KVP_OP_GET: if (kvp_get_value(hv_msg->kvp_hdr.pool, hv_msg->body.kvp_set.data.key, hv_msg->body.kvp_set.data.key_size, hv_msg->body.kvp_set.data.value, hv_msg->body.kvp_set.data.value_size)) strcpy(hv_msg->body.kvp_set.data.key, ""); break; case KVP_OP_DELETE: if (kvp_key_delete(hv_msg->kvp_hdr.pool, hv_msg->body.kvp_delete.key, hv_msg->body.kvp_delete.key_size)) strcpy(hv_msg->body.kvp_delete.key, ""); break; default: break; } if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE) goto kvp_done; if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) { kvp_pool_enumerate(hv_msg->kvp_hdr.pool, hv_msg->body.kvp_enum_data.index, hv_msg->body.kvp_enum_data.data.key, HV_KVP_EXCHANGE_MAX_KEY_SIZE, hv_msg->body.kvp_enum_data.data.value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); goto kvp_done; } hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; key_name = (char *)hv_msg->body.kvp_enum_data.data.key; key_value = (char *)hv_msg->body.kvp_enum_data.data.value; switch (hv_msg->body.kvp_enum_data.index) { case FullyQualifiedDomainName: kvp_get_domain_name(key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "FullyQualifiedDomainName"); break; case IntegrationServicesVersion: strcpy(key_name, "IntegrationServicesVersion"); strcpy(key_value, lic_version); break; case NetworkAddressIPv4: kvp_get_ip_address(AF_INET, key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "NetworkAddressIPv4"); break; case NetworkAddressIPv6: kvp_get_ip_address(AF_INET6, key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "NetworkAddressIPv6"); break; case OSBuildNumber: strcpy(key_value, os_build); strcpy(key_name, "OSBuildNumber"); break; case OSName: strcpy(key_value, os_name); strcpy(key_name, "OSName"); break; case OSMajorVersion: strcpy(key_value, os_major); strcpy(key_name, "OSMajorVersion"); break; case OSMinorVersion: strcpy(key_value, os_minor); strcpy(key_name, "OSMinorVersion"); break; case OSVersion: strcpy(key_value, os_build); strcpy(key_name, "OSVersion"); break; case ProcessorArchitecture: strcpy(key_value, processor_arch); strcpy(key_name, "ProcessorArchitecture"); break; default: strcpy(key_value, "Unknown Key"); strcpy(key_name, ""); break; } kvp_done: incoming_cn_msg->id.idx = CN_KVP_IDX; incoming_cn_msg->id.val = CN_KVP_VAL; incoming_cn_msg->ack = 0; incoming_cn_msg->len = sizeof(struct hv_kvp_msg); len = netlink_send(fd, incoming_cn_msg); if (len < 0) { syslog(LOG_ERR, "net_link send failed; error:%d", len); exit(EXIT_FAILURE); } } }
static int netlink_receive(struct netlink_fd *fd, struct nlmsghdr *reply) { struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int got_reply = FALSE, len; char buf[16*1024]; iov.iov_base = buf; while (!got_reply) { int status; struct nlmsghdr *h; iov.iov_len = sizeof(buf); status = recvmsg(fd->fd, &msg, MSG_DONTWAIT); if (status < 0) { if (errno == EINTR) continue; if (errno == EAGAIN) return reply == NULL; fprintf(stderr, "Netlink overrun\n"); continue; } if (status == 0) { fprintf(stderr, "Netlink returned EOF\n"); return FALSE; } h = (struct nlmsghdr *) buf; while (NLMSG_OK(h, status)) { if (reply != NULL && h->nlmsg_seq == reply->nlmsg_seq) { len = h->nlmsg_len; if (len > reply->nlmsg_len) { fprintf(stderr, "Netlink message " "truncated\n"); len = reply->nlmsg_len; } memcpy(reply, h, len); got_reply = TRUE; } else if (h->nlmsg_type != NLMSG_DONE) { fprintf(stderr, "Unknown NLmsg: 0x%08x, len %d\n", h->nlmsg_type, h->nlmsg_len); } h = NLMSG_NEXT(h, status); } } return TRUE; } static int netlink_send(struct netlink_fd *fd, struct nlmsghdr *req) { struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*) req, .iov_len = req->nlmsg_len }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int status; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req->nlmsg_seq = ++fd->seq; status = sendmsg(fd->fd, &msg, 0); if (status < 0) { fprintf(stderr, "Cannot talk to rtnetlink\n"); return FALSE; } return TRUE; } static int netlink_talk(struct nlmsghdr *req, size_t replysize, struct nlmsghdr *reply) { struct netlink_fd fd; int ret = FALSE; if (!netlink_open(&fd)) return FALSE; if (reply == NULL) req->nlmsg_flags |= NLM_F_ACK; if (!netlink_send(&fd, req)) goto out; if (reply != NULL) { reply->nlmsg_len = replysize; ret = netlink_receive(&fd, reply); } else { ret = TRUE; } out: netlink_close(&fd); return ret; } int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname) { struct { struct nlmsghdr n; union { struct rtmsg r; struct ifinfomsg i; }; char buf[1024]; } req; struct rtmsg *r = NLMSG_DATA(&req.n); struct rtattr *rta[RTA_MAX+1]; struct rtattr *rtax[RTAX_MAX+1]; struct rtattr *ifla[IFLA_MAX+1]; int index; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_family = dst->sa_family; netlink_add_rtaddr_l(&req.n, sizeof(req), RTA_DST, dst); req.r.rtm_dst_len = 32; if (!netlink_talk(&req.n, sizeof(req), &req.n)) return FALSE; netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r), RTM_PAYLOAD(&req.n)); if (mtu != NULL) { if (rta[RTA_METRICS] == NULL) return FALSE; netlink_parse_rtattr(rtax, RTAX_MAX, RTA_DATA(rta[RTA_METRICS]), RTA_PAYLOAD(rta[RTA_METRICS])); if (rtax[RTAX_MTU] == NULL) return FALSE; *mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]); } if (ifname != NULL) { if (rta[RTA_OIF] == NULL) return FALSE; index = *(int*) RTA_DATA(rta[RTA_OIF]); memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETLINK; req.i.ifi_index = index; if (!netlink_talk(&req.n, sizeof(req), &req.n)) return FALSE; netlink_parse_rtattr(ifla, IFLA_MAX, IFLA_RTA(r), IFLA_PAYLOAD(&req.n)); if (ifla[IFLA_IFNAME] == NULL) return FALSE; memcpy(ifname, RTA_DATA(ifla[IFLA_IFNAME]), RTA_PAYLOAD(ifla[IFLA_IFNAME])); } return TRUE; }
extern int genetlink_send(struct genl_handler *handler, struct genlmsg *genlmsg) { return netlink_send(&handler->nlh, (struct nlmsg *)&genlmsg->nlmsghdr); }
int main(void) { int fd, len, nl_group; int error; struct cn_msg *message; struct pollfd pfd; struct nlmsghdr *incoming_msg; struct cn_msg *incoming_cn_msg; int op; struct hv_vss_msg *vss_msg; char *vss_send_buffer; char *vss_recv_buffer; size_t vss_recv_buffer_len; if (daemon(1, 0)) return 1; openlog("Hyper-V VSS", 0, LOG_USER); syslog(LOG_INFO, "VSS starting; pid is:%d", getpid()); vss_recv_buffer_len = NLMSG_HDRLEN + sizeof(struct cn_msg) + sizeof(struct hv_vss_msg); vss_send_buffer = calloc(1, vss_recv_buffer_len); vss_recv_buffer = calloc(1, vss_recv_buffer_len); if (!(vss_send_buffer && vss_recv_buffer)) { syslog(LOG_ERR, "Failed to allocate netlink buffers"); exit(EXIT_FAILURE); } fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (fd < 0) { syslog(LOG_ERR, "netlink socket creation failed; error:%d %s", errno, strerror(errno)); exit(EXIT_FAILURE); } addr.nl_family = AF_NETLINK; addr.nl_pad = 0; addr.nl_pid = 0; addr.nl_groups = 0; error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); if (error < 0) { syslog(LOG_ERR, "bind failed; error:%d %s", errno, strerror(errno)); close(fd); exit(EXIT_FAILURE); } nl_group = CN_VSS_IDX; if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)) < 0) { syslog(LOG_ERR, "setsockopt failed; error:%d %s", errno, strerror(errno)); close(fd); exit(EXIT_FAILURE); } /* * Register ourselves with the kernel. */ message = (struct cn_msg *)vss_send_buffer; message->id.idx = CN_VSS_IDX; message->id.val = CN_VSS_VAL; message->ack = 0; vss_msg = (struct hv_vss_msg *)message->data; vss_msg->vss_hdr.operation = VSS_OP_REGISTER; message->len = sizeof(struct hv_vss_msg); len = netlink_send(fd, message); if (len < 0) { syslog(LOG_ERR, "netlink_send failed; error:%d %s", errno, strerror(errno)); close(fd); exit(EXIT_FAILURE); } pfd.fd = fd; while (1) { struct sockaddr *addr_p = (struct sockaddr *) &addr; socklen_t addr_l = sizeof(addr); pfd.events = POLLIN; pfd.revents = 0; if (poll(&pfd, 1, -1) < 0) { syslog(LOG_ERR, "poll failed; error:%d %s", errno, strerror(errno)); if (errno == EINVAL) { close(fd); exit(EXIT_FAILURE); } else continue; } len = recvfrom(fd, vss_recv_buffer, vss_recv_buffer_len, 0, addr_p, &addr_l); if (len < 0) { syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", addr.nl_pid, errno, strerror(errno)); close(fd); return -1; } if (addr.nl_pid) { syslog(LOG_WARNING, "Received packet from untrusted pid:%u", addr.nl_pid); continue; } incoming_msg = (struct nlmsghdr *)vss_recv_buffer; if (incoming_msg->nlmsg_type != NLMSG_DONE) continue; incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); vss_msg = (struct hv_vss_msg *)incoming_cn_msg->data; op = vss_msg->vss_hdr.operation; error = HV_S_OK; switch (op) { case VSS_OP_FREEZE: case VSS_OP_THAW: error = vss_operate(op); if (error) error = HV_E_FAIL; break; default: syslog(LOG_ERR, "Illegal op:%d\n", op); } vss_msg->error = error; len = netlink_send(fd, incoming_cn_msg); if (len < 0) { syslog(LOG_ERR, "net_link send failed; error:%d %s", errno, strerror(errno)); exit(EXIT_FAILURE); } } }
int main(int argc, char *argv[]) { int s; char buf[1024]; int len; struct nlmsghdr *reply; struct sockaddr_nl l_local; struct cn_msg *data; FILE *out; time_t tm; struct pollfd pfd; bool send_msgs = false; while ((s = getopt(argc, argv, "hs")) != -1) { switch (s) { case 's': send_msgs = true; break; case 'h': usage(); return 0; default: usage(); return 1; } } if (argc != optind) { out = fopen(argv[optind], "a+"); if (!out) { ulog("Unable to open %s for writing: %s\n", argv[1], strerror(errno)); out = stdout; } } else out = stdout; memset(buf, 0, sizeof(buf)); s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (s == -1) { perror("socket"); return -1; } l_local.nl_family = AF_NETLINK; l_local.nl_groups = -1; l_local.nl_pid = 0; ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL); if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) { perror("bind"); close(s); return -1; } #if 0 { int on = 0x57; setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on)); } #endif if (send_msgs) { int i, j; memset(buf, 0, sizeof(buf)); data = (struct cn_msg *)buf; data->id.idx = CN_TEST_IDX; data->id.val = CN_TEST_VAL; data->seq = seq++; data->ack = 0; data->len = 0; for (j=0; j<10; ++j) { for (i=0; i<1000; ++i) { len = netlink_send(s, data); } ulog("%d messages have been sent to %08x.%08x.\n", i, data->id.idx, data->id.val); } return 0; } pfd.fd = s; while (!need_exit) { pfd.events = POLLIN; pfd.revents = 0; switch (poll(&pfd, 1, -1)) { case 0: need_exit = 1; break; case -1: if (errno != EINTR) { need_exit = 1; break; } continue; } if (need_exit) break; memset(buf, 0, sizeof(buf)); len = recv(s, buf, sizeof(buf), 0); if (len == -1) { perror("recv buf"); close(s); return -1; } reply = (struct nlmsghdr *)buf; switch (reply->nlmsg_type) { case NLMSG_ERROR: fprintf(out, "Error message received.\n"); fflush(out); break; case NLMSG_DONE: data = (struct cn_msg *)NLMSG_DATA(reply); time(&tm); fprintf(out, "%.24s : [%x.%x] [%08u.%08u].\n", ctime(&tm), data->id.idx, data->id.val, data->seq, data->ack); fflush(out); break; default: break; } } close(s); return 0; }