mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	netlink: advertise incomplete dumps
Consider the following situation: * a dump that would show 8 entries, four in the first round, and four in the second * between the first and second rounds, 6 entries are removed * now the second round will not show any entry, and even if there is a sequence/generation counter the application will not know To solve this problem, add a new flag NLM_F_DUMP_INTR to the netlink header that indicates the dump wasn't consistent, this flag can also be set on the MSG_DONE message that terminates the dump, and as such above situation can be detected. To achieve this, add a sequence counter to the netlink callback struct. Of course, netlink code still needs to use this new functionality. The correct way to do that is to always set cb->seq when a dumpit callback is invoked and call nl_dump_check_consistent() for each new message. The core code will also call this function for the final MSG_DONE message. To make it usable with generic netlink, a new function genlmsg_nlhdr() is needed to obtain the netlink header from the genetlink user header. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
		
							parent
							
								
									c1c3daee97
								
							
						
					
					
						commit
						670dc2833d
					
				
					 4 changed files with 60 additions and 0 deletions
				
			
		| 
						 | 
					@ -48,6 +48,7 @@ struct nlmsghdr {
 | 
				
			||||||
#define NLM_F_MULTI		2	/* Multipart message, terminated by NLMSG_DONE */
 | 
					#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_ACK		4	/* Reply with ack, with zero or error code */
 | 
				
			||||||
#define NLM_F_ECHO		8	/* Echo this request 		*/
 | 
					#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 */
 | 
					/* Modifiers to GET request */
 | 
				
			||||||
#define NLM_F_ROOT	0x100	/* specify tree	root	*/
 | 
					#define NLM_F_ROOT	0x100	/* specify tree	root	*/
 | 
				
			||||||
| 
						 | 
					@ -221,6 +222,7 @@ struct netlink_callback {
 | 
				
			||||||
					struct netlink_callback *cb);
 | 
										struct netlink_callback *cb);
 | 
				
			||||||
	int			(*done)(struct netlink_callback *cb);
 | 
						int			(*done)(struct netlink_callback *cb);
 | 
				
			||||||
	int			family;
 | 
						int			family;
 | 
				
			||||||
 | 
						unsigned int		prev_seq, seq;
 | 
				
			||||||
	long			args[6];
 | 
						long			args[6];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,6 +159,38 @@ static inline void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq,
 | 
				
			||||||
	return (char *) hdr + GENL_HDRLEN;
 | 
						return (char *) hdr + GENL_HDRLEN;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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
 | 
					 * genlmsg_put_reply - Add generic netlink header to a reply message
 | 
				
			||||||
 * @skb: socket buffer holding the message
 | 
					 * @skb: socket buffer holding the message
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -638,6 +638,30 @@ static inline int nlmsg_unicast(struct sock *sk, struct sk_buff *skb, u32 pid)
 | 
				
			||||||
	     nlmsg_ok(pos, rem); \
 | 
						     nlmsg_ok(pos, rem); \
 | 
				
			||||||
	     pos = nlmsg_next(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
 | 
					 * Netlink Attributes
 | 
				
			||||||
 **************************************************************************/
 | 
					 **************************************************************************/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1693,6 +1693,8 @@ static int netlink_dump(struct sock *sk)
 | 
				
			||||||
	if (!nlh)
 | 
						if (!nlh)
 | 
				
			||||||
		goto errout_skb;
 | 
							goto errout_skb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nl_dump_check_consistent(cb, nlh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(nlmsg_data(nlh), &len, sizeof(len));
 | 
						memcpy(nlmsg_data(nlh), &len, sizeof(len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sk_filter(sk, skb))
 | 
						if (sk_filter(sk, skb))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue