diff options
| -rw-r--r-- | include/linux/netlink.h | 2 | ||||
| -rw-r--r-- | include/net/genetlink.h | 32 | ||||
| -rw-r--r-- | include/net/netlink.h | 24 | ||||
| -rw-r--r-- | net/netlink/af_netlink.c | 2 | 
4 files changed, 60 insertions, 0 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 4c4ac3f3ce5..8d1bcec5cc0 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -48,6 +48,7 @@ struct nlmsghdr {  #define NLM_F_MULTI		2	/* Multipart message, terminated by NLMSG_DONE */  #define NLM_F_ACK		4	/* Reply with ack, with zero or error code */  #define NLM_F_ECHO		8	/* Echo this request 		*/ +#define NLM_F_DUMP_INTR		16	/* Dump was inconsistent due to sequence change */  /* Modifiers to GET request */  #define NLM_F_ROOT	0x100	/* specify tree	root	*/ @@ -221,6 +222,7 @@ struct netlink_callback {  					struct netlink_callback *cb);  	int			(*done)(struct netlink_callback *cb);  	int			family; +	unsigned int		prev_seq, seq;  	long			args[6];  }; diff --git a/include/net/genetlink.h b/include/net/genetlink.h index d420f28b6d6..82d8d09faa4 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -160,6 +160,38 @@ static inline void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq,  }  /** + * genlmsg_nlhdr - Obtain netlink header from user specified header + * @user_hdr: user header as returned from genlmsg_put() + * @family: generic netlink family + * + * Returns pointer to netlink header. + */ +static inline struct nlmsghdr *genlmsg_nlhdr(void *user_hdr, +					     struct genl_family *family) +{ +	return (struct nlmsghdr *)((char *)user_hdr - +				   family->hdrsize - +				   GENL_HDRLEN - +				   NLMSG_HDRLEN); +} + +/** + * genl_dump_check_consistent - check if sequence is consistent and advertise if not + * @cb: netlink callback structure that stores the sequence number + * @user_hdr: user header as returned from genlmsg_put() + * @family: generic netlink family + * + * Cf. nl_dump_check_consistent(), this just provides a wrapper to make it + * simpler to use with generic netlink. + */ +static inline void genl_dump_check_consistent(struct netlink_callback *cb, +					      void *user_hdr, +					      struct genl_family *family) +{ +	nl_dump_check_consistent(cb, genlmsg_nlhdr(user_hdr, family)); +} + +/**   * genlmsg_put_reply - Add generic netlink header to a reply message   * @skb: socket buffer holding the message   * @info: receiver info diff --git a/include/net/netlink.h b/include/net/netlink.h index 02740a94f10..98c185441be 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -638,6 +638,30 @@ static inline int nlmsg_unicast(struct sock *sk, struct sk_buff *skb, u32 pid)  	     nlmsg_ok(pos, rem); \  	     pos = nlmsg_next(pos, &(rem))) +/** + * nl_dump_check_consistent - check if sequence is consistent and advertise if not + * @cb: netlink callback structure that stores the sequence number + * @nlh: netlink message header to write the flag to + * + * This function checks if the sequence (generation) number changed during dump + * and if it did, advertises it in the netlink message header. + * + * The correct way to use it is to set cb->seq to the generation counter when + * all locks for dumping have been acquired, and then call this function for + * each message that is generated. + * + * Note that due to initialisation concerns, 0 is an invalid sequence number + * and must not be used by code that uses this functionality. + */ +static inline void +nl_dump_check_consistent(struct netlink_callback *cb, +			 struct nlmsghdr *nlh) +{ +	if (cb->prev_seq && cb->seq != cb->prev_seq) +		nlh->nlmsg_flags |= NLM_F_DUMP_INTR; +	cb->prev_seq = cb->seq; +} +  /**************************************************************************   * Netlink Attributes   **************************************************************************/ diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 6ef64adf736..a7ec8512f55 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1693,6 +1693,8 @@ static int netlink_dump(struct sock *sk)  	if (!nlh)  		goto errout_skb; +	nl_dump_check_consistent(cb, nlh); +  	memcpy(nlmsg_data(nlh), &len, sizeof(len));  	if (sk_filter(sk, skb))  |