void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) { struct sk_buff *skb; struct nlmsghdr *rep; struct nlmsgerr *errmsg; int size; if (err == 0) size = NLMSG_SPACE(sizeof(struct nlmsgerr)); else size = NLMSG_SPACE(4 + NLMSG_ALIGN(nlh->nlmsg_len)); skb = alloc_skb(size, GFP_KERNEL); if (!skb) { struct sock *sk; sk = netlink_lookup(in_skb->sk->sk_protocol, NETLINK_CB(in_skb).pid); if (sk) { sk->sk_err = ENOBUFS; sk->sk_error_report(sk); sock_put(sk); } return; } rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, NLMSG_ERROR, sizeof(struct nlmsgerr)); errmsg = NLMSG_DATA(rep); errmsg->error = err; memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(struct nlmsghdr)); netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); }
static int notify(void *data, int len, int gfp_mask) { struct sk_buff *skb; struct nlmsghdr *nlh; static u32 seq = 0; if (!(skb = alloc_skb(NLMSG_SPACE(len), gfp_mask))) return -ENOMEM; nlh = __nlmsg_put(skb, ietd_pid, seq++, NLMSG_DONE, len - sizeof(*nlh), 0); memcpy(NLMSG_DATA(nlh), data, len); return netlink_unicast(nl, skb, ietd_pid, 0); }
static int netlink_dump(struct sock *sk) { struct netlink_opt *nlk = nlk_sk(sk); struct netlink_callback *cb; struct sk_buff *skb; struct nlmsghdr *nlh; int len; skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); if (!skb) return -ENOBUFS; spin_lock(&nlk->cb_lock); cb = nlk->cb; if (cb == NULL) { spin_unlock(&nlk->cb_lock); kfree_skb(skb); return -EINVAL; } len = cb->dump(skb, cb); if (len > 0) { spin_unlock(&nlk->cb_lock); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, len); return 0; } nlh = __nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLMSG_DONE, sizeof(int)); nlh->nlmsg_flags |= NLM_F_MULTI; memcpy(NLMSG_DATA(nlh), &len, sizeof(len)); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); cb->done(cb); nlk->cb = NULL; spin_unlock(&nlk->cb_lock); netlink_destroy_callback(cb); sock_put(sk); return 0; }
static int iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, void *payload, int size) { struct sk_buff *skb; struct nlmsghdr *nlh; int len = NLMSG_SPACE(size); int flags = multi ? NLM_F_MULTI : 0; int t = done ? NLMSG_DONE : type; skb = alloc_skb(len, GFP_KERNEL); if (!skb) { return -ENOMEM; } nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh))); nlh->nlmsg_flags = flags; memcpy(NLMSG_DATA(nlh), payload, size); netlink_unicast(nls, skb, pid, MSG_DONTWAIT); return 0; }
/* event_mutex supposed to be held */ static int __event_send(const void *buf, int buf_len) { int res = 0, len; struct sk_buff *skb; struct nlmsghdr *nlh; static u32 seq; /* protected by event_mutex */ TRACE_ENTRY(); if (ctr_open_state != ISCSI_CTR_OPEN_STATE_OPEN) goto out; len = NLMSG_SPACE(buf_len); skb = alloc_skb(NLMSG_SPACE(len), GFP_KERNEL); if (skb == NULL) { PRINT_ERROR("alloc_skb() failed (len %d)", len); res = -ENOMEM; goto out; } nlh = __nlmsg_put(skb, iscsid_pid, seq++, NLMSG_DONE, len - sizeof(*nlh), 0); memcpy(NLMSG_DATA(nlh), buf, buf_len); res = netlink_unicast(nl, skb, iscsid_pid, 0); if (res <= 0) { if (res != -ECONNREFUSED) PRINT_ERROR("netlink_unicast() failed: %d", res); else TRACE(TRACE_MINOR, "netlink_unicast() failed: %s. " "Not functioning user space?", "Connection refused"); goto out; } out: TRACE_EXIT_RES(res); return res; }
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; }