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); }
struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) { int protocol = ssk->sk_protocol; struct sock *sock; struct netlink_opt *nlk; sock = netlink_lookup(protocol, pid); if (!sock) return ERR_PTR(-ECONNREFUSED); /* Don't bother queuing skb if kernel socket has no input function */ nlk = nlk_sk(sock); if ((nlk->pid == 0 && !nlk->data_ready) || (sock->sk_state == NETLINK_CONNECTED && nlk->dst_pid != nlk_sk(ssk)->pid)) { sock_put(sock); return ERR_PTR(-ECONNREFUSED); } return sock; }
int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, struct nlmsghdr *nlh, int (*dump)(struct sk_buff *skb, struct netlink_callback*), int (*done)(struct netlink_callback*)) { struct netlink_callback *cb; struct sock *sk; struct netlink_opt *nlk; cb = kmalloc(sizeof(*cb), GFP_KERNEL); if (cb == NULL) return -ENOBUFS; memset(cb, 0, sizeof(*cb)); cb->dump = dump; cb->done = done; cb->nlh = nlh; atomic_inc(&skb->users); cb->skb = skb; sk = netlink_lookup(ssk->sk_protocol, NETLINK_CB(skb).pid); if (sk == NULL) { netlink_destroy_callback(cb); return -ECONNREFUSED; } nlk = nlk_sk(sk); /* A dump is in progress... */ spin_lock(&nlk->cb_lock); if (nlk->cb) { spin_unlock(&nlk->cb_lock); netlink_destroy_callback(cb); sock_put(sk); return -EBUSY; } nlk->cb = cb; spin_unlock(&nlk->cb_lock); netlink_dump(sk); return 0; }
int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock) { struct sock *sk; int len = skb->len; int protocol = ssk->protocol; long timeo; DECLARE_WAITQUEUE(wait, current); timeo = sock_sndtimeo(ssk, nonblock); retry: sk = netlink_lookup(protocol, pid); if (sk == NULL) goto no_dst; #ifdef NL_EMULATE_DEV if (sk->protinfo.af_netlink->handler) { skb_orphan(skb); len = sk->protinfo.af_netlink->handler(protocol, skb); sock_put(sk); return len; } #endif if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || test_bit(0, &sk->protinfo.af_netlink->state)) { if (!timeo) { if (ssk->protinfo.af_netlink->pid == 0) netlink_overrun(sk); sock_put(sk); kfree_skb(skb); return -EAGAIN; } __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&sk->protinfo.af_netlink->wait, &wait); if ((atomic_read(&sk->rmem_alloc) > sk->rcvbuf || test_bit(0, &sk->protinfo.af_netlink->state)) && !sk->dead) timeo = schedule_timeout(timeo); __set_current_state(TASK_RUNNING); remove_wait_queue(&sk->protinfo.af_netlink->wait, &wait); sock_put(sk); if (signal_pending(current)) { kfree_skb(skb); return sock_intr_errno(timeo); } goto retry; } skb_orphan(skb); skb_set_owner_r(skb, sk); skb_queue_tail(&sk->receive_queue, skb); sk->data_ready(sk, len); sock_put(sk); return len; no_dst: kfree_skb(skb); return -ECONNREFUSED; }