aboutsummaryrefslogtreecommitdiffstats
path: root/lib/lufa/Projects/Webserver
ModeNameSize
d---------Config79logstatsplain
-rw-r--r--Descriptors.c10623logstatsplain
-rw-r--r--Descriptors.h4979logstatsplain
-rw-r--r--LUFA Webserver RNDIS.inf1931logstatsplain
d---------Lib736logstatsplain
-rw-r--r--USBDeviceMode.c5419logstatsplain
-rw-r--r--USBDeviceMode.h1932logstatsplain
-rw-r--r--USBHostMode.c5411logstatsplain
-rw-r--r--USBHostMode.h1941logstatsplain
-rw-r--r--Webserver.c2199logstatsplain
-rw-r--r--Webserver.h2575logstatsplain
-rw-r--r--Webserver.txt5406logstatsplain
-rw-r--r--asf.xml4133logstatsplain
-rw-r--r--doxyfile104473logstatsplain
-rw-r--r--makefile1525logstatsplain
ref='#n271'>271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
/*  Xenbus code for netif backend
    Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
    Copyright (C) 2005 XenSource Ltd

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


#include <stdarg.h>
#include <linux/module.h>
#include <xen/xenbus.h>
#include <xen/net_driver_util.h>
#include "common.h"


#if 0
#undef DPRINTK
#define DPRINTK(fmt, args...) \
    printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
#endif


struct backend_info
{
	struct xenbus_device *dev;
	netif_t *netif;
	struct xenbus_watch backend_watch;
	XenbusState frontend_state;
};


static int connect_rings(struct backend_info *);
static void connect(struct backend_info *);
static void maybe_connect(struct backend_info *);
static void backend_changed(struct xenbus_watch *, const char **,
			    unsigned int);


static int netback_remove(struct xenbus_device *dev)
{
	struct backend_info *be = dev->data;

	if (be->backend_watch.node) {
		unregister_xenbus_watch(&be->backend_watch);
		kfree(be->backend_watch.node);
		be->backend_watch.node = NULL;
	}
	if (be->netif) {
		netif_disconnect(be->netif);
		be->netif = NULL;
	}
	kfree(be);
	dev->data = NULL;
	return 0;
}


/**
 * Entry point to this code when a new device is created.  Allocate the basic
 * structures, and watch the store waiting for the hotplug scripts to tell us
 * the device's handle.  Switch to InitWait.
 */
static int netback_probe(struct xenbus_device *dev,
			 const struct xenbus_device_id *id)
{
	int err;
	struct backend_info *be = kzalloc(sizeof(struct backend_info),
					  GFP_KERNEL);
	if (!be) {
		xenbus_dev_fatal(dev, -ENOMEM,
				 "allocating backend structure");
		return -ENOMEM;
	}

	be->dev = dev;
	dev->data = be;

	err = xenbus_watch_path2(dev, dev->nodename, "handle",
				 &be->backend_watch, backend_changed);
	if (err)
		goto fail;

	err = xenbus_switch_state(dev, XenbusStateInitWait);
	if (err) {
		goto fail;
	}

	return 0;

fail:
	DPRINTK("failed");
	netback_remove(dev);
	return err;
}


/**
 * Handle the creation of the hotplug script environment.  We add the script
 * and vif variables to the environment, for the benefit of the vif-* hotplug
 * scripts.
 */
static int netback_uevent(struct xenbus_device *xdev, char **envp,
			  int num_envp, char *buffer, int buffer_size)
{
	struct backend_info *be = xdev->data;
	netif_t *netif = be->netif;
	int i = 0, length = 0;
	char *val;

	DPRINTK("netback_uevent");

	val = xenbus_read(XBT_NULL, xdev->nodename, "script", NULL);
	if (IS_ERR(val)) {
		int err = PTR_ERR(val);
		xenbus_dev_fatal(xdev, err, "reading script");
		return err;
	}
	else {
		add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
			       &length, "script=%s", val);
		kfree(val);
	}

	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
		       "vif=%s", netif->dev->name);

	envp[i] = NULL;

	return 0;
}


/**
 * Callback received when the hotplug scripts have placed the handle node.
 * Read it, and create a netif structure.  If the frontend is ready, connect.
 */
static void backend_changed(struct xenbus_watch *watch,
			    const char **vec, unsigned int len)
{
	int err;
	long handle;
	struct backend_info *be
		= container_of(watch, struct backend_info, backend_watch);
	struct xenbus_device *dev = be->dev;

	DPRINTK("");

	err = xenbus_scanf(XBT_NULL, dev->nodename, "handle", "%li", &handle);
	if (XENBUS_EXIST_ERR(err)) {
		/* Since this watch will fire once immediately after it is
		   registered, we expect this.  Ignore it, and wait for the
		   hotplug scripts. */
		return;
	}
	if (err != 1) {
		xenbus_dev_fatal(dev, err, "reading handle");
		return;
	}

	if (be->netif == NULL) {
		u8 be_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };

		be->netif = netif_alloc(dev->otherend_id, handle, be_mac);
		if (IS_ERR(be->netif)) {
			err = PTR_ERR(be->netif);
			be->netif = NULL;
			xenbus_dev_fatal(dev, err, "creating interface");
			return;
		}

		kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);

		maybe_connect(be);
	}
}


/**
 * Callback received when the frontend's state changes.
 */
static void frontend_changed(struct xenbus_device *dev,
			     XenbusState frontend_state)
{
	struct backend_info *be = dev->data;

	DPRINTK("");

	be->frontend_state = frontend_state;

	switch (frontend_state) {
	case XenbusStateInitialising:
	case XenbusStateInitialised:
		break;

	case XenbusStateConnected:
		maybe_connect(be);
		break;

	case XenbusStateClosing:
		xenbus_switch_state(dev, XenbusStateClosing);
		break;

	case XenbusStateClosed:
		if (be->netif != NULL)
			kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
		device_unregister(&dev->dev);
		break;

	case XenbusStateUnknown:
	case XenbusStateInitWait:
	default:
		xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
				 frontend_state);
		break;
	}
}


/* ** Connection ** */


static void maybe_connect(struct backend_info *be)
{
	if (be->netif && (be->frontend_state == XenbusStateConnected))
		connect(be);
}

static void xen_net_read_rate(struct xenbus_device *dev,
			      unsigned long *bytes, unsigned long *usec)
{
	char *s, *e;
	unsigned long b, u;
	char *ratestr;

	/* Default to unlimited bandwidth. */
	*bytes = ~0UL;
	*usec = 0;

	ratestr = xenbus_read(XBT_NULL, dev->nodename, "rate", NULL);
	if (IS_ERR(ratestr))
		return;

	s = ratestr;
	b = simple_strtoul(s, &e, 10);
	if ((s == e) || (*e != ','))
		goto fail;

	s = e + 1;
	u = simple_strtoul(s, &e, 10);
	if ((s == e) || (*e != '\0'))
		goto fail;

	*bytes = b;
	*usec = u;

	kfree(ratestr);
	return;

 fail:
	WPRINTK("Failed to parse network rate limit. Traffic unlimited.\n");
	kfree(ratestr);
}


static void connect(struct backend_info *be)
{
	int err;
	struct xenbus_device *dev = be->dev;

	err = connect_rings(be);
	if (err)
		return;

	err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
	if (err) {
		xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
		return;
	}

	xen_net_read_rate(dev, &be->netif->credit_bytes,
			  &be->netif->credit_usec);
	be->netif->remaining_credit = be->netif->credit_bytes;

	xenbus_switch_state(dev, XenbusStateConnected);
}


static int connect_rings(struct backend_info *be)
{
	struct xenbus_device *dev = be->dev;
	unsigned long tx_ring_ref, rx_ring_ref;
	unsigned int evtchn;
	int err;

	DPRINTK("");

	err = xenbus_gather(XBT_NULL, dev->otherend,
			    "tx-ring-ref", "%lu", &tx_ring_ref,
			    "rx-ring-ref", "%lu", &rx_ring_ref,
			    "event-channel", "%u", &evtchn, NULL);
	if (err) {
		xenbus_dev_fatal(dev, err,
				 "reading %s/ring-ref and event-channel",
				 dev->otherend);
		return err;
	}

	/* Map the shared frame, irq etc. */
	err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
	if (err) {
		xenbus_dev_fatal(dev, err,
				 "mapping shared-frames %lu/%lu port %u",
				 tx_ring_ref, rx_ring_ref, evtchn);
		return err;
	}
	return 0;
}


/* ** Driver Registration ** */


static struct xenbus_device_id netback_ids[] = {
	{ "vif" },
	{ "" }
};


static struct xenbus_driver netback = {
	.name = "vif",
	.owner = THIS_MODULE,
	.ids = netback_ids,
	.probe = netback_probe,
	.remove = netback_remove,
	.uevent = netback_uevent,
	.otherend_changed = frontend_changed,
};


void netif_xenbus_init(void)
{
	xenbus_register_backend(&netback);
}