Commit ca374290 authored by Sergey Ryazanov's avatar Sergey Ryazanov Committed by David S. Miller
Browse files

wwan: core: support default netdev creation



Most, if not each WWAN device driver will create a netdev for the
default data channel. Therefore, add an option for the WWAN netdev ops
registration function to create a default netdev for the WWAN device.

A WWAN device driver should pass a default data channel link id to the
ops registering function to request the creation of a default netdev, or
a special value WWAN_NO_DEFAULT_LINK to inform the WWAN core that the
default netdev should not be created.

For now, only wwan_hwsim utilize the default link creation option. Other
drivers will be reworked next.

Signed-off-by: default avatarSergey Ryazanov <ryazanov.s.a@gmail.com>
CC: M Chetan Kumar <m.chetan.kumar@intel.com>
CC: Intel Corporation <linuxwwan@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9f0248ea
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -397,7 +397,8 @@ static int mhi_net_probe(struct mhi_device *mhi_dev,
	struct net_device *ndev;
	int err;

	err = wwan_register_ops(&cntrl->mhi_dev->dev, &mhi_wwan_ops, mhi_dev);
	err = wwan_register_ops(&cntrl->mhi_dev->dev, &mhi_wwan_ops, mhi_dev,
				WWAN_NO_DEFAULT_LINK);
	if (err)
		return err;

+2 −1
Original line number Diff line number Diff line
@@ -317,7 +317,8 @@ struct iosm_wwan *ipc_wwan_init(struct iosm_imem *ipc_imem, struct device *dev)
	ipc_wwan->dev = dev;
	ipc_wwan->ipc_imem = ipc_imem;

	if (wwan_register_ops(ipc_wwan->dev, &iosm_wwan_ops, ipc_wwan)) {
	if (wwan_register_ops(ipc_wwan->dev, &iosm_wwan_ops, ipc_wwan,
			      WWAN_NO_DEFAULT_LINK)) {
		kfree(ipc_wwan);
		return NULL;
	}
+74 −1
Original line number Diff line number Diff line
@@ -903,17 +903,81 @@ static struct rtnl_link_ops wwan_rtnl_link_ops __read_mostly = {
	.policy = wwan_rtnl_policy,
};

static void wwan_create_default_link(struct wwan_device *wwandev,
				     u32 def_link_id)
{
	struct nlattr *tb[IFLA_MAX + 1], *linkinfo[IFLA_INFO_MAX + 1];
	struct nlattr *data[IFLA_WWAN_MAX + 1];
	struct net_device *dev;
	struct nlmsghdr *nlh;
	struct sk_buff *msg;

	/* Forge attributes required to create a WWAN netdev. We first
	 * build a netlink message and then parse it. This looks
	 * odd, but such approach is less error prone.
	 */
	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (WARN_ON(!msg))
		return;
	nlh = nlmsg_put(msg, 0, 0, RTM_NEWLINK, 0, 0);
	if (WARN_ON(!nlh))
		goto free_attrs;

	if (nla_put_string(msg, IFLA_PARENT_DEV_NAME, dev_name(&wwandev->dev)))
		goto free_attrs;
	tb[IFLA_LINKINFO] = nla_nest_start(msg, IFLA_LINKINFO);
	if (!tb[IFLA_LINKINFO])
		goto free_attrs;
	linkinfo[IFLA_INFO_DATA] = nla_nest_start(msg, IFLA_INFO_DATA);
	if (!linkinfo[IFLA_INFO_DATA])
		goto free_attrs;
	if (nla_put_u32(msg, IFLA_WWAN_LINK_ID, def_link_id))
		goto free_attrs;
	nla_nest_end(msg, linkinfo[IFLA_INFO_DATA]);
	nla_nest_end(msg, tb[IFLA_LINKINFO]);

	nlmsg_end(msg, nlh);

	/* The next three parsing calls can not fail */
	nlmsg_parse_deprecated(nlh, 0, tb, IFLA_MAX, NULL, NULL);
	nla_parse_nested_deprecated(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
				    NULL, NULL);
	nla_parse_nested_deprecated(data, IFLA_WWAN_MAX,
				    linkinfo[IFLA_INFO_DATA], NULL, NULL);

	rtnl_lock();

	dev = rtnl_create_link(&init_net, "wwan%d", NET_NAME_ENUM,
			       &wwan_rtnl_link_ops, tb, NULL);
	if (WARN_ON(IS_ERR(dev)))
		goto unlock;

	if (WARN_ON(wwan_rtnl_newlink(&init_net, dev, tb, data, NULL))) {
		free_netdev(dev);
		goto unlock;
	}

unlock:
	rtnl_unlock();

free_attrs:
	nlmsg_free(msg);
}

/**
 * wwan_register_ops - register WWAN device ops
 * @parent: Device to use as parent and shared by all WWAN ports and
 *	created netdevs
 * @ops: operations to register
 * @ctxt: context to pass to operations
 * @def_link_id: id of the default link that will be automatically created by
 *	the WWAN core for the WWAN device. The default link will not be created
 *	if the passed value is WWAN_NO_DEFAULT_LINK.
 *
 * Returns: 0 on success, a negative error code on failure
 */
int wwan_register_ops(struct device *parent, const struct wwan_ops *ops,
		      void *ctxt)
		      void *ctxt, u32 def_link_id)
{
	struct wwan_device *wwandev;

@@ -932,6 +996,15 @@ int wwan_register_ops(struct device *parent, const struct wwan_ops *ops,
	wwandev->ops = ops;
	wwandev->ops_ctxt = ctxt;

	/* NB: we do not abort ops registration in case of default link
	 * creation failure. Link ops is the management interface, while the
	 * default link creation is a service option. And we should not prevent
	 * a user from manually creating a link latter if service option failed
	 * now.
	 */
	if (def_link_id != WWAN_NO_DEFAULT_LINK)
		wwan_create_default_link(wwandev, def_link_id);

	return 0;
}
EXPORT_SYMBOL_GPL(wwan_register_ops);
+1 −1
Original line number Diff line number Diff line
@@ -288,7 +288,7 @@ static struct wwan_hwsim_dev *wwan_hwsim_dev_new(void)

	INIT_WORK(&dev->del_work, wwan_hwsim_dev_del_work);

	err = wwan_register_ops(&dev->dev, &wwan_hwsim_wwan_rtnl_ops, dev);
	err = wwan_register_ops(&dev->dev, &wwan_hwsim_wwan_rtnl_ops, dev, 1);
	if (err)
		goto err_unreg_dev;

+7 −1
Original line number Diff line number Diff line
@@ -126,6 +126,12 @@ void wwan_port_txon(struct wwan_port *port);
 */
void *wwan_port_get_drvdata(struct wwan_port *port);

/*
 * Used to indicate that the WWAN core should not create a default network
 * link.
 */
#define WWAN_NO_DEFAULT_LINK		U32_MAX

/**
 * struct wwan_ops - WWAN device ops
 * @priv_size: size of private netdev data area
@@ -143,7 +149,7 @@ struct wwan_ops {
};

int wwan_register_ops(struct device *parent, const struct wwan_ops *ops,
		      void *ctxt);
		      void *ctxt, u32 def_link_id);

void wwan_unregister_ops(struct device *parent);