{
struct module *module = NULL;
struct netlink_sock *nlk;
- unsigned int groups;
int err = 0;
sock->state = SS_UNCONNECTED;
if (nl_table[protocol].registered &&
try_module_get(nl_table[protocol].module))
module = nl_table[protocol].module;
- groups = nl_table[protocol].groups;
netlink_unlock_table();
if ((err = __netlink_create(sock, protocol)) < 0)
return 0;
netlink_remove(sk);
+ sock_orphan(sk);
nlk = nlk_sk(sk);
spin_lock(&nlk->cb_lock);
/* OK. Socket is unlinked, and, therefore,
no new packets will arrive */
- sock_orphan(sk);
sock->sk = NULL;
wake_up_interruptible_all(&nlk->wait);
copied = len;
}
- skb->h.raw = skb->data;
+ skb_reset_transport_header(skb);
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (msg->msg_name) {
scm_recv(sock, msg, siocb->scm, flags);
+ if (flags & MSG_TRUNC)
+ copied = skb->len;
+
out:
netlink_rcv_wake(sk);
return err ? : copied;
return -ECONNREFUSED;
}
nlk = nlk_sk(sk);
- /* A dump is in progress... */
+ /* A dump or destruction is in progress... */
spin_lock(&nlk->cb_lock);
- if (nlk->cb) {
+ if (nlk->cb || sock_flag(sk, SOCK_DEAD)) {
spin_unlock(&nlk->cb_lock);
netlink_destroy_callback(cb);
sock_put(sk);
netlink_dump(sk);
sock_put(sk);
- return 0;
+
+ /* We successfully started a dump, by returning -EINTR we
+ * signal the queue mangement to interrupt processing of
+ * any netlink messages so userspace gets a chance to read
+ * the results. */
+ return -EINTR;
}
void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
}
static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
- struct nlmsghdr *, int *))
+ struct nlmsghdr *))
{
struct nlmsghdr *nlh;
int err;
while (skb->len >= nlmsg_total_size(0)) {
- nlh = (struct nlmsghdr *) skb->data;
+ nlh = nlmsg_hdr(skb);
+ err = 0;
if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len)
return 0;
- if (cb(skb, nlh, &err) < 0) {
- /* Not an error, but we have to interrupt processing
- * here. Note: that in this case we do not pull
- * message from skb, it will be processed later.
- */
- if (err == 0)
- return -1;
+ /* Only requests are handled by the kernel */
+ if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
+ goto skip;
+
+ /* Skip control messages */
+ if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
+ goto skip;
+
+ err = cb(skb, nlh);
+ if (err == -EINTR) {
+ /* Not an error, but we interrupt processing */
+ netlink_queue_skip(nlh, skb);
+ return err;
+ }
+skip:
+ if (nlh->nlmsg_flags & NLM_F_ACK || err)
netlink_ack(skb, nlh, err);
- } else if (nlh->nlmsg_flags & NLM_F_ACK)
- netlink_ack(skb, nlh, 0);
netlink_queue_skip(nlh, skb);
}
*
* qlen must be initialized to 0 before the initial entry, afterwards
* the function may be called repeatedly until qlen reaches 0.
+ *
+ * The callback function may return -EINTR to signal that processing
+ * of netlink messages shall be interrupted. In this case the message
+ * currently being processed will NOT be requeued onto the receive
+ * queue.
*/
void netlink_run_queue(struct sock *sk, unsigned int *qlen,
- int (*cb)(struct sk_buff *, struct nlmsghdr *, int *))
+ int (*cb)(struct sk_buff *, struct nlmsghdr *))
{
struct sk_buff *skb;
return 0;
}
-static struct file_operations netlink_seq_fops = {
+static const struct file_operations netlink_seq_fops = {
.owner = THIS_MODULE,
.open = netlink_seq_open,
.read = seq_read,
EXPORT_SYMBOL(netlink_dump_start);
EXPORT_SYMBOL(netlink_kernel_create);
EXPORT_SYMBOL(netlink_register_notifier);
-EXPORT_SYMBOL(netlink_set_err);
EXPORT_SYMBOL(netlink_set_nonroot);
EXPORT_SYMBOL(netlink_unicast);
EXPORT_SYMBOL(netlink_unregister_notifier);