11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * James Leu (jleu@mindspring.net).
4cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 by various other people who didn't put their name here.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Licensed under the GPL.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95134d8fea06ab51459fd095d091d1e6f73a44553Jeff Dike#include <linux/init.h>
10cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike#include <linux/netdevice.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "etap.h"
1237185b33240870719b6b5913a46e6a441f1ae96fAl Viro#include <net_kern.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ethertap_init {
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *dev_name;
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *gate_addr;
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void etap_init(struct net_device *dev, void *data)
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uml_net_private *pri;
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ethertap_data *epri;
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ethertap_init *init = data;
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2517c324fa80914e5b39d423dfd1a3cd61a3ec9866Wang Chen	pri = netdev_priv(dev);
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epri = (struct ethertap_data *) pri->user;
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epri->dev_name = init->dev_name;
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epri->gate_addr = init->gate_addr;
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epri->data_fd = -1;
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epri->control_fd = -1;
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	epri->dev = dev;
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
335134d8fea06ab51459fd095d091d1e6f73a44553Jeff Dike	printk(KERN_INFO "ethertap backend - %s", epri->dev_name);
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (epri->gate_addr != NULL)
355134d8fea06ab51459fd095d091d1e6f73a44553Jeff Dike		printk(KERN_CONT ", IP = %s", epri->gate_addr);
365134d8fea06ab51459fd095d091d1e6f73a44553Jeff Dike	printk(KERN_CONT "\n");
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dikestatic int etap_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dike	len = net_recvfrom(fd, skb_mac_header(skb),
44b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dike			   skb->dev->mtu + 2 + ETH_HEADER_ETHERTAP);
45cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike	if (len <= 0)
46b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dike		return(len);
47b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dike
48b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dike	skb_pull(skb, 2);
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len -= 2;
50cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike	return len;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dikestatic int etap_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
55b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dike	skb_push(skb, 2);
56b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dike	return net_send(fd, skb->data, skb->len);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
595e7672ec3f059f764fcc5c78216e24bb16c44dbaJeff Dikeconst struct net_kern_info ethertap_kern_info = {
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init			= etap_init,
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.protocol		= eth_protocol,
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read			= etap_read,
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write 			= etap_write,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ethertap_setup(char *str, char **mac_out, void *data)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ethertap_init *init = data;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*init = ((struct ethertap_init)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ .dev_name 	= NULL,
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  .gate_addr 	= NULL });
73cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike	if (tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    &init->gate_addr))
75cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike		return 0;
76cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike	if (init->dev_name == NULL) {
77cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike		printk(KERN_ERR "ethertap_setup : Missing tap device name\n");
78cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike		return 0;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81cd1ae0e49bdd814cfaa2e5ab28cff21a30e20085Jeff Dike	return 1;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct transport ethertap_transport = {
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.list 		= LIST_HEAD_INIT(ethertap_transport.list),
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name 		= "ethertap",
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.setup  	= ethertap_setup,
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.user 		= &ethertap_user_info,
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.kern 		= &ethertap_kern_info,
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.private_size 	= sizeof(struct ethertap_data),
91b53f35a8093e6aed7e8e880eaa0b89a3d2fdfb0aJeff Dike	.setup_size 	= sizeof(struct ethertap_init),
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int register_ethertap(void)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register_transport(&ethertap_transport);
97f4c57a78e2c49f188babf675ba0a9264b5374c26Jeff Dike	return 0;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1008210fd2a9fe4b36e99ab777a1a81eb47b703c235Jeff Dikelate_initcall(register_ethertap);
101