diff options
Diffstat (limited to 'lib/kobject_uevent.c')
| -rw-r--r-- | lib/kobject_uevent.c | 110 | 
1 files changed, 63 insertions, 47 deletions
| diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index f237a09a5862..2615074d3de5 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -294,10 +294,60 @@ static void cleanup_uevent_env(struct subprocess_info *info)  }  #endif +static int kobject_uevent_net_broadcast(struct kobject *kobj, +					struct kobj_uevent_env *env, +					const char *action_string, +					const char *devpath) +{ +	int retval = 0; +#if defined(CONFIG_NET) +	struct sk_buff *skb = NULL; +	struct uevent_sock *ue_sk; + +	/* send netlink message */ +	list_for_each_entry(ue_sk, &uevent_sock_list, list) { +		struct sock *uevent_sock = ue_sk->sk; + +		if (!netlink_has_listeners(uevent_sock, 1)) +			continue; + +		if (!skb) { +			/* allocate message with the maximum possible size */ +			size_t len = strlen(action_string) + strlen(devpath) + 2; +			char *scratch; + +			retval = -ENOMEM; +			skb = alloc_skb(len + env->buflen, GFP_KERNEL); +			if (!skb) +				continue; + +			/* add header */ +			scratch = skb_put(skb, len); +			sprintf(scratch, "%s@%s", action_string, devpath); + +			skb_put_data(skb, env->buf, env->buflen); + +			NETLINK_CB(skb).dst_group = 1; +		} + +		retval = netlink_broadcast_filtered(uevent_sock, skb_get(skb), +						    0, 1, GFP_KERNEL, +						    kobj_bcast_filter, +						    kobj); +		/* ENOBUFS should be handled in userspace */ +		if (retval == -ENOBUFS || retval == -ESRCH) +			retval = 0; +	} +	consume_skb(skb); +#endif +	return retval; +} +  static void zap_modalias_env(struct kobj_uevent_env *env)  {  	static const char modalias_prefix[] = "MODALIAS="; -	int i; +	size_t len; +	int i, j;  	for (i = 0; i < env->envp_idx;) {  		if (strncmp(env->envp[i], modalias_prefix, @@ -306,11 +356,18 @@ static void zap_modalias_env(struct kobj_uevent_env *env)  			continue;  		} -		if (i != env->envp_idx - 1) -			memmove(&env->envp[i], &env->envp[i + 1], -				sizeof(env->envp[i]) * env->envp_idx - 1); +		len = strlen(env->envp[i]) + 1; + +		if (i != env->envp_idx - 1) { +			memmove(env->envp[i], env->envp[i + 1], +				env->buflen - len); + +			for (j = i; j < env->envp_idx - 1; j++) +				env->envp[j] = env->envp[j + 1] - len; +		}  		env->envp_idx--; +		env->buflen -= len;  	}  } @@ -336,9 +393,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,  	const struct kset_uevent_ops *uevent_ops;  	int i = 0;  	int retval = 0; -#ifdef CONFIG_NET -	struct uevent_sock *ue_sk; -#endif  	pr_debug("kobject: '%s' (%p): %s\n",  		 kobject_name(kobj), kobj, __func__); @@ -460,46 +514,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,  		mutex_unlock(&uevent_sock_mutex);  		goto exit;  	} - -#if defined(CONFIG_NET) -	/* send netlink message */ -	list_for_each_entry(ue_sk, &uevent_sock_list, list) { -		struct sock *uevent_sock = ue_sk->sk; -		struct sk_buff *skb; -		size_t len; - -		if (!netlink_has_listeners(uevent_sock, 1)) -			continue; - -		/* allocate message with the maximum possible size */ -		len = strlen(action_string) + strlen(devpath) + 2; -		skb = alloc_skb(len + env->buflen, GFP_KERNEL); -		if (skb) { -			char *scratch; - -			/* add header */ -			scratch = skb_put(skb, len); -			sprintf(scratch, "%s@%s", action_string, devpath); - -			/* copy keys to our continuous event payload buffer */ -			for (i = 0; i < env->envp_idx; i++) { -				len = strlen(env->envp[i]) + 1; -				scratch = skb_put(skb, len); -				strcpy(scratch, env->envp[i]); -			} - -			NETLINK_CB(skb).dst_group = 1; -			retval = netlink_broadcast_filtered(uevent_sock, skb, -							    0, 1, GFP_KERNEL, -							    kobj_bcast_filter, -							    kobj); -			/* ENOBUFS should be handled in userspace */ -			if (retval == -ENOBUFS || retval == -ESRCH) -				retval = 0; -		} else -			retval = -ENOMEM; -	} -#endif +	retval = kobject_uevent_net_broadcast(kobj, env, action_string, +					      devpath);  	mutex_unlock(&uevent_sock_mutex);  #ifdef CONFIG_UEVENT_HELPER |