/**
 * rmnet_unassociate_network_device() - Unassociate network device
 * @dev:      Device to unassociate
 *
 * Frees all structures generate for device. Unregisters rx_handler
 * todo: needs to do some sanity verification first (is device in use, etc...)
 *
 * Return:
 *      - RMNET_CONFIG_OK if successful
 *      - RMNET_CONFIG_NO_SUCH_DEVICE dev is null
 *      - RMNET_CONFIG_INVALID_REQUEST if device is not already associated
 *      - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
 */
int rmnet_unassociate_network_device(struct net_device *dev)
{
	struct rmnet_phys_ep_conf_s *config;
	ASSERT_RTNL();

	LOGL("%s(%s);", __func__, dev->name);

	if (!dev)
		return RMNET_CONFIG_NO_SUCH_DEVICE;

	if (!_rmnet_is_physical_endpoint_associated(dev))
		return RMNET_CONFIG_INVALID_REQUEST;

	config = (struct rmnet_phys_ep_conf_s *)
		rcu_dereference(dev->rx_handler_data);

	if (!config)
		return RMNET_CONFIG_UNKNOWN_ERROR;

	kfree(config);

	netdev_rx_handler_unregister(dev);

	return RMNET_CONFIG_OK;
}
示例#2
0
/**
 * rmnet_config_notify_cb() - Callback for netdevice notifier chain
 * @nb:       Notifier block data
 * @event:    Netdevice notifier event ID
 * @data:     Contains a net device for which we are getting notified
 *
 * Return:
 *      - result of NOTIFY_DONE()
 */
int rmnet_config_notify_cb(struct notifier_block *nb,
				  unsigned long event, void *data)
{
	struct net_device *dev = (struct net_device *)data;

	if (!dev)
		BUG();

	LOGL("(..., %lu, %s)", event, dev->name);

	switch (event) {
	case NETDEV_UNREGISTER_FINAL:
	case NETDEV_UNREGISTER:
		trace_rmnet_unregister_cb_entry(dev);
		if (_rmnet_is_physical_endpoint_associated(dev)) {
			LOGH("Kernel is trying to unregister %s", dev->name);
			rmnet_force_unassociate_device(dev);
		}
		trace_rmnet_unregister_cb_exit(dev);
		break;

	default:
		trace_rmnet_unregister_cb_unhandled(dev);
		LOGD("Unhandeled event [%lu]", event);
		break;
	}

	return NOTIFY_DONE;
}
/**
 * _rmnet_get_phys_ep_config() - Get physical ep config for an associated device
 * @dev:      Device to get endpoint configuration from
 *
 * Return:
 *     - pointer to configuration if successful
 *     - 0 (null) if device is not associated
 */
static inline struct rmnet_phys_ep_conf_s *_rmnet_get_phys_ep_config
							(struct net_device *dev)
{
	if (_rmnet_is_physical_endpoint_associated(dev))
		return (struct rmnet_phys_ep_conf_s *)
			rcu_dereference(dev->rx_handler_data);
	else
		return 0;
}
示例#4
0
/**
 * rmnet_unset_logical_endpoint_config() - Un-set logical endpoing configuration
 * on a device
 * @dev:            Device to set endpoint configuration on
 * @config_id:      logical endpoint id on device
 *
 * Retrieves the logical_endpoint_config structure and frees the egress device.
 * Network device must already have association with RmNet Data driver
 *
 * Return:
 *      - RMNET_CONFIG_OK if successful
 *      - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
 *      - RMNET_CONFIG_NO_SUCH_DEVICE device is not associated
 *      - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range
 */
int rmnet_unset_logical_endpoint_config(struct net_device *dev,
					int config_id)
{
	LOGL("(%s, %d);", dev->name, config_id);

	if (!dev
	    || ((!_rmnet_is_physical_endpoint_associated(dev))
	    && (!rmnet_vnd_is_vnd(dev)))) {
		return RMNET_CONFIG_NO_SUCH_DEVICE;
	}

	return _rmnet_unset_logical_endpoint_config(dev, config_id);
}
示例#5
0
/**
 * rmnet_associate_network_device() - Associate network device
 * @dev:      Device to register with RmNet data
 *
 * Typically used on physical network devices. Registers RX handler and private
 * metadata structures.
 *
 * Return:
 *      - RMNET_CONFIG_OK if successful
 *      - RMNET_CONFIG_NO_SUCH_DEVICE dev is null
 *      - RMNET_CONFIG_INVALID_REQUEST if the device to be associated is a vnd
 *      - RMNET_CONFIG_DEVICE_IN_USE if dev rx_handler is already filled
 *      - RMNET_CONFIG_DEVICE_IN_USE if netdev_rx_handler_register() fails
 */
int rmnet_associate_network_device(struct net_device *dev)
{
	struct rmnet_phys_ep_conf_s *config;
	int rc;
	ASSERT_RTNL();

	LOGL("(%s);\n", dev->name);

	if (!dev)
		return RMNET_CONFIG_NO_SUCH_DEVICE;

	if (_rmnet_is_physical_endpoint_associated(dev)) {
		LOGM("%s is already regestered", dev->name);
		return RMNET_CONFIG_DEVICE_IN_USE;
	}

	if (rmnet_vnd_is_vnd(dev)) {
		LOGM("%s is a vnd", dev->name);
		return RMNET_CONFIG_INVALID_REQUEST;
	}

	config = (struct rmnet_phys_ep_conf_s *)
		 kmalloc(sizeof(struct rmnet_phys_ep_conf_s), GFP_ATOMIC);

	if (!config)
		return RMNET_CONFIG_NOMEM;

	memset(config, 0, sizeof(struct rmnet_phys_ep_conf_s));
	config->dev = dev;
	spin_lock_init(&config->agg_lock);

	rc = netdev_rx_handler_register(dev, rmnet_rx_handler, config);

	if (rc) {
		LOGM("netdev_rx_handler_register returns %d", rc);
		kfree(config);
		return RMNET_CONFIG_DEVICE_IN_USE;
	}

	/* Explicitly hold a reference to the device */
	dev_hold(dev);
	trace_rmnet_associate(dev);
	return RMNET_CONFIG_OK;
}
示例#6
0
static void _rmnet_netlink_get_network_device_associated
					(struct rmnet_nl_msg_s *rmnet_header,
					 struct rmnet_nl_msg_s *resp_rmnet)
{
	struct net_device *dev;

	_RMNET_NETLINK_NULL_CHECKS();
	resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;

	dev = dev_get_by_name(&init_net, rmnet_header->data);
	if (!dev) {
		resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
		return;
	}

	resp_rmnet->return_code = _rmnet_is_physical_endpoint_associated(dev);
	resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA;
	dev_put(dev);
}
/**
 * rmnet_set_logical_endpoint_config() - Set logical endpoing configuration on a device
 * @dev:            Device to set endpoint configuration on
 * @config_id:      logical endpoint id on device
 * @rmnet_mode:     endpoint mode. Values from: rmnet_config_endpoint_modes_e
 * @egress_device:  device node to forward packet to once done processing in
 *                  ingress/egress handlers
 *
 * Creates a logical_endpoint_config structure and fills in the information from
 * function arguments. Calls _rmnet_set_logical_endpoint_config() to finish
 * configuration. Network device must already have association with RmNet Data
 * driver
 *
 * Return:
 *      - RMNET_CONFIG_OK if successful
 *      - RMNET_CONFIG_BAD_EGRESS_DEVICE if egress device is null
 *      - RMNET_CONFIG_BAD_EGRESS_DEVICE if egress device is not handled by
 *                                       RmNet data module
 *      - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
 *      - RMNET_CONFIG_NO_SUCH_DEVICE if device to set config on is null
 *      - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range
 */
int rmnet_set_logical_endpoint_config(struct net_device *dev,
				      int config_id,
				      uint8_t rmnet_mode,
				      struct net_device *egress_dev)
{
	struct rmnet_logical_ep_conf_s epconfig;

	LOGL("%s(%s, %d, %d, %s);",
	      __func__, dev->name, config_id, rmnet_mode, egress_dev->name);

	if (!egress_dev
	    || ((!_rmnet_is_physical_endpoint_associated(egress_dev))
	    && (!rmnet_vnd_is_vnd(egress_dev)))) {
		return RMNET_CONFIG_BAD_EGRESS_DEVICE;
	}

	memset(&epconfig, 0, sizeof(struct rmnet_logical_ep_conf_s));
	epconfig.refcount = 1;
	epconfig.rmnet_mode = rmnet_mode;
	epconfig.egress_dev = egress_dev;

	return _rmnet_set_logical_endpoint_config(dev, config_id, &epconfig);
}
/**
 * rmnet_associate_network_device() - Associate network device
 * @dev:      Device to register with RmNet data
 *
 * Typically used on physical network devices. Registers RX handler and private
 * metadata structures.
 *
 * Return:
 *      - RMNET_CONFIG_OK if successful
 *      - RMNET_CONFIG_NO_SUCH_DEVICE dev is null
 *      - RMNET_CONFIG_DEVICE_IN_USE if dev rx_handler is already filled
 *      - RMNET_CONFIG_DEVICE_IN_USE if netdev_rx_handler_register() fails
 */
int rmnet_associate_network_device(struct net_device *dev)
{
	struct rmnet_phys_ep_conf_s *config;
	int rc;
	ASSERT_RTNL();

	LOGL("%s(%s);", __func__, dev->name);

	if (!dev)
		return RMNET_CONFIG_NO_SUCH_DEVICE;

	if (_rmnet_is_physical_endpoint_associated(dev)) {
		LOGM("%s(): %s is already regestered\n", __func__, dev->name);
		return RMNET_CONFIG_DEVICE_IN_USE;
	}

	config = (struct rmnet_phys_ep_conf_s *)
		 kmalloc(sizeof(struct rmnet_phys_ep_conf_s), GFP_ATOMIC);

	if (!config)
		return RMNET_CONFIG_NOMEM;

	memset(config, 0, sizeof(struct rmnet_phys_ep_conf_s));
	config->dev = dev;
	spin_lock_init(&config->agg_lock);

	rc = netdev_rx_handler_register(dev, rmnet_rx_handler, config);

	if (rc) {
		LOGM("%s(): netdev_rx_handler_register returns %d\n",
		     __func__, rc);
		kfree(config);
		return RMNET_CONFIG_DEVICE_IN_USE;
	}

	return RMNET_CONFIG_OK;
}
示例#9
0
/**
 * rmnet_unassociate_network_device() - Unassociate network device
 * @dev:      Device to unassociate
 *
 * Frees all structures generate for device. Unregisters rx_handler
 * todo: needs to do some sanity verification first (is device in use, etc...)
 *
 * Return:
 *      - RMNET_CONFIG_OK if successful
 *      - RMNET_CONFIG_NO_SUCH_DEVICE dev is null
 *      - RMNET_CONFIG_INVALID_REQUEST if device is not already associated
 *      - RMNET_CONFIG_DEVICE_IN_USE if device has logical ep that wasn't unset
 *      - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
 */
int rmnet_unassociate_network_device(struct net_device *dev)
{
	struct rmnet_phys_ep_conf_s *config;
	int config_id = RMNET_LOCAL_LOGICAL_ENDPOINT;
	struct rmnet_logical_ep_conf_s *epconfig_l;
	ASSERT_RTNL();

	LOGL("(%s);", dev->name);

	if (!dev)
		return RMNET_CONFIG_NO_SUCH_DEVICE;

	if (!_rmnet_is_physical_endpoint_associated(dev))
		return RMNET_CONFIG_INVALID_REQUEST;

	for (; config_id < RMNET_DATA_MAX_LOGICAL_EP; config_id++) {
		epconfig_l = _rmnet_get_logical_ep(dev, config_id);
		if (epconfig_l && epconfig_l->refcount)
			return RMNET_CONFIG_DEVICE_IN_USE;
	}

	config = (struct rmnet_phys_ep_conf_s *)
		rcu_dereference(dev->rx_handler_data);

	if (!config)
		return RMNET_CONFIG_UNKNOWN_ERROR;

	kfree(config);

	netdev_rx_handler_unregister(dev);

	/* Explicitly release the reference from the device */
	dev_put(dev);
	trace_rmnet_unassociate(dev);
	return RMNET_CONFIG_OK;
}
示例#10
0
/**
 * rmnet_force_unassociate_device() - Force a device to unassociate
 * @dev:       Device to unassociate
 *
 * Return:
 *      - void
 */
static void rmnet_force_unassociate_device(struct net_device *dev)
{
	int i, j;
	struct net_device *vndev;
	struct rmnet_logical_ep_conf_s *cfg;
	struct rmnet_free_vnd_work *vnd_work;
	ASSERT_RTNL();

	if (!dev)
		BUG();

	if (!_rmnet_is_physical_endpoint_associated(dev)) {
		LOGM("%s", "Called on unassociated device, skipping");
		return;
	}

	trace_rmnet_unregister_cb_clear_vnds(dev);
	vnd_work = (struct rmnet_free_vnd_work *)
		kmalloc(sizeof(struct rmnet_free_vnd_work), GFP_KERNEL);
	if (!vnd_work) {
		LOGH("%s", "Out of Memory");
		return;
	}
	INIT_WORK(&vnd_work->work, _rmnet_free_vnd_later);
	vnd_work->count = 0;

	/* Check the VNDs for offending mappings */
	for (i = 0, j = 0; i < RMNET_DATA_MAX_VND &&
				j < RMNET_DATA_MAX_VND; i++) {
		vndev = rmnet_vnd_get_by_id(i);
		if (!vndev) {
			LOGL("VND %d not in use; skipping", i);
			continue;
		}
		cfg = rmnet_vnd_get_le_config(vndev);
		if (!cfg) {
			LOGH("Got NULL config from VND %d", i);
			BUG();
			continue;
		}
		if (cfg->refcount && (cfg->egress_dev == dev)) {
			rmnet_unset_logical_endpoint_config(vndev,
						  RMNET_LOCAL_LOGICAL_ENDPOINT);
			vnd_work->vnd_id[j] = i;
			j++;
		}
	}
	if (j > 0) {
		vnd_work->count = j;
		schedule_work(&vnd_work->work);
	} else {
		kfree(vnd_work);
	}


	/* Clear the mappings on the phys ep */
	trace_rmnet_unregister_cb_clear_lepcs(dev);
	rmnet_unset_logical_endpoint_config(dev, RMNET_LOCAL_LOGICAL_ENDPOINT);
	for (i = 0; i < RMNET_DATA_MAX_LOGICAL_EP; i++)
		rmnet_unset_logical_endpoint_config(dev, i);
	rmnet_unassociate_network_device(dev);
}