Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33f72e6f authored by Bill Hong's avatar Bill Hong Committed by David S. Miller
Browse files

l2tp : multicast notification to the registered listeners



Previously l2tp module did not provide any means for the user space to
get notified when tunnels/sessions are added/modified/deleted.
This change contains the following
- create a multicast group for the listeners to register.
- notify the registered listeners when the tunnels/sessions are
  created/modified/deleted.

Signed-off-by: default avatarBill Hong <bhong@brocade.com>
Reviewed-by: default avatarStephen Hemminger <stephen@networkplumber.org>
Reviewed-by: default avatarSven-Thorsten Dietrich <sven@brocade.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 957f094f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -178,5 +178,6 @@ enum l2tp_seqmode {
 */
#define L2TP_GENL_NAME		"l2tp"
#define L2TP_GENL_VERSION	0x1
#define L2TP_GENL_MCGROUP       "l2tp"

#endif /* _UAPI_LINUX_L2TP_H_ */
+91 −10
Original line number Diff line number Diff line
@@ -40,6 +40,18 @@ static struct genl_family l2tp_nl_family = {
	.netnsok	= true,
};

static const struct genl_multicast_group l2tp_multicast_group[] = {
	{
		.name = L2TP_GENL_MCGROUP,
	},
};

static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq,
			       int flags, struct l2tp_tunnel *tunnel, u8 cmd);
static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq,
				int flags, struct l2tp_session *session,
				u8 cmd);

/* Accessed under genl lock */
static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX];

@@ -97,6 +109,52 @@ static int l2tp_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
	return ret;
}

static int l2tp_tunnel_notify(struct genl_family *family,
			      struct genl_info *info,
			      struct l2tp_tunnel *tunnel,
			      u8 cmd)
{
	struct sk_buff *msg;
	int ret;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		return -ENOMEM;

	ret = l2tp_nl_tunnel_send(msg, info->snd_portid, info->snd_seq,
				  NLM_F_ACK, tunnel, cmd);

	if (ret >= 0)
		return genlmsg_multicast_allns(family, msg, 0,	0, GFP_ATOMIC);

	nlmsg_free(msg);

	return ret;
}

static int l2tp_session_notify(struct genl_family *family,
			       struct genl_info *info,
			       struct l2tp_session *session,
			       u8 cmd)
{
	struct sk_buff *msg;
	int ret;

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		return -ENOMEM;

	ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq,
				   NLM_F_ACK, session, cmd);

	if (ret >= 0)
		return genlmsg_multicast_allns(family, msg, 0,	0, GFP_ATOMIC);

	nlmsg_free(msg);

	return ret;
}

static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info)
{
	u32 tunnel_id;
@@ -188,6 +246,9 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
		break;
	}

	if (ret >= 0)
		ret = l2tp_tunnel_notify(&l2tp_nl_family, info,
					 tunnel, L2TP_CMD_TUNNEL_CREATE);
out:
	return ret;
}
@@ -211,6 +272,9 @@ static int l2tp_nl_cmd_tunnel_delete(struct sk_buff *skb, struct genl_info *info
		goto out;
	}

	l2tp_tunnel_notify(&l2tp_nl_family, info,
			   tunnel, L2TP_CMD_TUNNEL_DELETE);

	(void) l2tp_tunnel_delete(tunnel);

out:
@@ -239,12 +303,15 @@ static int l2tp_nl_cmd_tunnel_modify(struct sk_buff *skb, struct genl_info *info
	if (info->attrs[L2TP_ATTR_DEBUG])
		tunnel->debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);

	ret = l2tp_tunnel_notify(&l2tp_nl_family, info,
				 tunnel, L2TP_CMD_TUNNEL_MODIFY);

out:
	return ret;
}

static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int flags,
			       struct l2tp_tunnel *tunnel)
			       struct l2tp_tunnel *tunnel, u8 cmd)
{
	void *hdr;
	struct nlattr *nest;
@@ -254,8 +321,7 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla
	struct ipv6_pinfo *np = NULL;
#endif

	hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags,
			  L2TP_CMD_TUNNEL_GET);
	hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, cmd);
	if (!hdr)
		return -EMSGSIZE;

@@ -359,7 +425,7 @@ static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info)
	}

	ret = l2tp_nl_tunnel_send(msg, info->snd_portid, info->snd_seq,
				  NLM_F_ACK, tunnel);
				  NLM_F_ACK, tunnel, L2TP_CMD_TUNNEL_GET);
	if (ret < 0)
		goto err_out;

@@ -385,7 +451,7 @@ static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback

		if (l2tp_nl_tunnel_send(skb, NETLINK_CB(cb->skb).portid,
					cb->nlh->nlmsg_seq, NLM_F_MULTI,
					tunnel) <= 0)
					tunnel, L2TP_CMD_TUNNEL_GET) <= 0)
			goto out;

		ti++;
@@ -539,6 +605,13 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
		ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id,
			session_id, peer_session_id, &cfg);

	if (ret >= 0) {
		session = l2tp_session_find(net, tunnel, session_id);
		if (session)
			ret = l2tp_session_notify(&l2tp_nl_family, info, session,
						  L2TP_CMD_SESSION_CREATE);
	}

out:
	return ret;
}
@@ -555,6 +628,9 @@ static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *inf
		goto out;
	}

	l2tp_session_notify(&l2tp_nl_family, info,
			    session, L2TP_CMD_SESSION_DELETE);

	pw_type = session->pwtype;
	if (pw_type < __L2TP_PWTYPE_MAX)
		if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete)
@@ -601,12 +677,15 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf
	if (info->attrs[L2TP_ATTR_MRU])
		session->mru = nla_get_u16(info->attrs[L2TP_ATTR_MRU]);

	ret = l2tp_session_notify(&l2tp_nl_family, info,
				  session, L2TP_CMD_SESSION_MODIFY);

out:
	return ret;
}

static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int flags,
				struct l2tp_session *session)
				struct l2tp_session *session, u8 cmd)
{
	void *hdr;
	struct nlattr *nest;
@@ -615,7 +694,7 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl

	sk = tunnel->sock;

	hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, L2TP_CMD_SESSION_GET);
	hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, cmd);
	if (!hdr)
		return -EMSGSIZE;

@@ -699,7 +778,7 @@ static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info)
	}

	ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq,
				   0, session);
				   0, session, L2TP_CMD_SESSION_GET);
	if (ret < 0)
		goto err_out;

@@ -737,7 +816,7 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback

		if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid,
					 cb->nlh->nlmsg_seq, NLM_F_MULTI,
					 session) <= 0)
					 session, L2TP_CMD_SESSION_GET) <= 0)
			break;

		si++;
@@ -896,7 +975,9 @@ EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops);
static int l2tp_nl_init(void)
{
	pr_info("L2TP netlink interface\n");
	return genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops);
	return genl_register_family_with_ops_groups(&l2tp_nl_family,
						    l2tp_nl_ops,
						    l2tp_multicast_group);
}

static void l2tp_nl_cleanup(void)