static void dpdk_nl_process_response(void *usockp, struct nlmsghdr *nlh) { __u32 seq; unsigned int multi_flag = 0; bool write = true; struct vr_message *resp; struct nlmsghdr *resp_nlh; struct genlmsghdr *genlh, *resp_genlh; struct nlattr *resp_nla; seq = nlh->nlmsg_seq; genlh = (struct genlmsghdr *)((unsigned char *)nlh + NLMSG_HDRLEN); /* Process responses */ while ((resp = (struct vr_message *)vr_message_dequeue_response())) { if (!write) { vr_message_free(resp); continue; } if (!vr_response_queue_empty()) { multi_flag = NLM_F_MULTI; } else { multi_flag = 0; } /* Update Netlink headers */ resp_nlh = dpdk_nl_message_hdr(resp); resp_nlh->nlmsg_len = dpdk_nl_message_len(resp); resp_nlh->nlmsg_type = nlh->nlmsg_type; resp_nlh->nlmsg_flags = multi_flag; resp_nlh->nlmsg_seq = seq; resp_nlh->nlmsg_pid = 0; resp_genlh = (struct genlmsghdr *)((unsigned char *)resp_nlh + NLMSG_HDRLEN); memcpy(resp_genlh, genlh, sizeof(*genlh)); resp_nla = (struct nlattr *)((unsigned char *)resp_genlh + GENL_HDRLEN); resp_nla->nla_len = resp->vr_message_len; resp_nla->nla_type = NL_ATTR_VR_MESSAGE_PROTOCOL; if (vr_usocket_message_write(usockp, resp) < 0) { write = false; vr_usocket_close(usockp); } } return; }
static int netlink_trans_request(struct sk_buff *in_skb, struct genl_info *info) { char *buf; unsigned int len; uint32_t multi_flag; struct nlmsghdr *rep, *nlh = info->nlhdr; struct genlmsghdr *genlh; struct nlattr **aap = info->attrs; struct nlattr *nla; struct vr_message request, *response; struct sk_buff *skb; uint32_t netlink_id; if (!aap || !(nla = aap[NL_ATTR_VR_MESSAGE_PROTOCOL])) return -EINVAL; request.vr_message_buf = nla_data(nla); request.vr_message_len = nla_len(nla); vr_message_request(&request); #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) netlink_id = NETLINK_CB(in_skb).pid; #else netlink_id = NETLINK_CB(in_skb).portid; #endif multi_flag = 0; while ((response = vr_message_dequeue_response())) { if ((multi_flag == 0) && (!vr_response_queue_empty())) multi_flag = NLM_F_MULTI; buf = response->vr_message_buf; skb = netlink_skb(buf); if (!skb) continue; len = response->vr_message_len; len += GENL_HDRLEN + NLA_HDRLEN; len = NLMSG_ALIGN(len); rep = __nlmsg_put(skb, netlink_id, nlh->nlmsg_seq, nlh->nlmsg_type, len, multi_flag); genlh = nlmsg_data(rep); memcpy(genlh, info->genlhdr, sizeof(*genlh)); nla = (struct nlattr *)((char *)genlh + GENL_HDRLEN); nla->nla_len = response->vr_message_len; nla->nla_type = NL_ATTR_VR_MESSAGE_PROTOCOL; netlink_unicast(in_skb->sk, skb, netlink_id, MSG_DONTWAIT); response->vr_message_buf = NULL; vr_message_free(response); } if (multi_flag) { skb = alloc_skb(NLMSG_HDRLEN, GFP_ATOMIC); if (!skb) return 0; __nlmsg_put(skb, netlink_id, nlh->nlmsg_seq, NLMSG_DONE, 0, 0); netlink_unicast(in_skb->sk, skb, netlink_id, MSG_DONTWAIT); } return 0; }
NTSTATUS KsyncHandleWrite(PKSYNC_DEVICE_CONTEXT ctx, uint8_t *buffer, size_t buffer_size) { struct vr_message request; struct vr_message *response; uint32_t multi_flag; int ret; /* Received buffer contains tightly packed Netlink headers, thus we can just increment appropriate headers */ struct nlmsghdr *nlh = (struct nlmsghdr *)(buffer); struct genlmsghdr *genlh = (struct genlmsghdr *)(nlh + 1); struct nlattr *nla = (struct nlattr *)(genlh + 1); request.vr_message_buf = NLA_DATA(nla); request.vr_message_len = NLA_LEN(nla); ret = vr_message_request(&request); if (ret) { if (vr_send_response(ret)) { return STATUS_INVALID_PARAMETER; } } multi_flag = 0; while ((response = vr_message_dequeue_response())) { if (!multi_flag && !vr_response_queue_empty()) multi_flag = NLM_F_MULTI; char *data = response->vr_message_buf - NETLINK_HEADER_LEN; size_t data_len = NLMSG_ALIGN(response->vr_message_len + NETLINK_HEADER_LEN); struct nlmsghdr *nlh_resp = (struct nlmsghdr *)(data); nlh_resp->nlmsg_len = data_len; nlh_resp->nlmsg_type = nlh->nlmsg_type; nlh_resp->nlmsg_flags = multi_flag; nlh_resp->nlmsg_seq = nlh->nlmsg_seq; nlh_resp->nlmsg_pid = 0; /* 'genlmsghdr' should be put directly after 'nlmsghdr', thus we can just increment previous header pointer */ struct genlmsghdr *genlh_resp = (struct genlmsghdr *)(nlh_resp + 1); WinRawMemCpy(genlh_resp, genlh, sizeof(*genlh_resp)); /* 'nlattr' should be put directly after 'genlmsghdr', thus we can just increment previous header pointer */ struct nlattr *nla_resp = (struct nlattr *)(genlh_resp + 1); nla_resp->nla_len = response->vr_message_len; nla_resp->nla_type = NL_ATTR_VR_MESSAGE_PROTOCOL; PKSYNC_RESPONSE ks_resp = KsyncResponseCreate(); if (ks_resp != NULL) { ks_resp->message_len = data_len; WinRawMemCpy(ks_resp->buffer, data, ks_resp->message_len); KsyncAppendResponse(ctx, ks_resp); } else { return STATUS_INSUFFICIENT_RESOURCES; } vr_message_free(response); } if (multi_flag) { PKSYNC_RESPONSE ks_resp = KsyncResponseCreate(); if (ks_resp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } struct nlmsghdr *nlh_done = (struct nlmsghdr *)ks_resp->buffer; nlh_done->nlmsg_len = NLMSG_HDRLEN; nlh_done->nlmsg_type = NLMSG_DONE; nlh_done->nlmsg_flags = 0; nlh_done->nlmsg_seq = nlh->nlmsg_seq; nlh_done->nlmsg_pid = 0; ks_resp->message_len = NLMSG_HDRLEN; KsyncAppendResponse(ctx, ks_resp); } return STATUS_SUCCESS; }