ethertap_kern.c 2.5 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
J
Jeff Dike 已提交
2
 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
L
Linus Torvalds 已提交
3
 * James Leu (jleu@mindspring.net).
J
Jeff Dike 已提交
4
 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
L
Linus Torvalds 已提交
5 6 7 8 9
 * Copyright (C) 2001 by various other people who didn't put their name here.
 * Licensed under the GPL.
 */

#include "linux/init.h"
J
Jeff Dike 已提交
10
#include <linux/netdevice.h>
L
Linus Torvalds 已提交
11
#include "etap.h"
J
Jeff Dike 已提交
12
#include "net_kern.h"
L
Linus Torvalds 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

struct ethertap_init {
	char *dev_name;
	char *gate_addr;
};

static void etap_init(struct net_device *dev, void *data)
{
	struct uml_net_private *pri;
	struct ethertap_data *epri;
	struct ethertap_init *init = data;

	pri = dev->priv;
	epri = (struct ethertap_data *) pri->user;
	epri->dev_name = init->dev_name;
	epri->gate_addr = init->gate_addr;
	epri->data_fd = -1;
	epri->control_fd = -1;
	epri->dev = dev;

	printk("ethertap backend - %s", epri->dev_name);
	if (epri->gate_addr != NULL)
		printk(", IP = %s", epri->gate_addr);
	printk("\n");
}

static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
{
	int len;

	*skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
J
Jeff Dike 已提交
44 45
	if (*skb == NULL)
		return -ENOMEM;
46
	len = net_recvfrom(fd, skb_mac_header(*skb),
L
Linus Torvalds 已提交
47
			   (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
J
Jeff Dike 已提交
48 49
	if (len <= 0)
		return len;
L
Linus Torvalds 已提交
50 51
	skb_pull(*skb, 2);
	len -= 2;
J
Jeff Dike 已提交
52
	return len;
L
Linus Torvalds 已提交
53 54 55 56
}

static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
{
J
Jeff Dike 已提交
57
	if (skb_headroom(*skb) < 2) {
L
Linus Torvalds 已提交
58 59 60 61
	  	struct sk_buff *skb2;

		skb2 = skb_realloc_headroom(*skb, 2);
		dev_kfree_skb(*skb);
J
Jeff Dike 已提交
62 63
		if (skb2 == NULL)
			return -ENOMEM;
L
Linus Torvalds 已提交
64 65 66
		*skb = skb2;
	}
	skb_push(*skb, 2);
J
Jeff Dike 已提交
67
	return net_send(fd, (*skb)->data, (*skb)->len);
L
Linus Torvalds 已提交
68 69
}

J
Jeff Dike 已提交
70
const struct net_kern_info ethertap_kern_info = {
L
Linus Torvalds 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83
	.init			= etap_init,
	.protocol		= eth_protocol,
	.read			= etap_read,
	.write 			= etap_write,
};

int ethertap_setup(char *str, char **mac_out, void *data)
{
	struct ethertap_init *init = data;

	*init = ((struct ethertap_init)
		{ .dev_name 	= NULL,
		  .gate_addr 	= NULL });
J
Jeff Dike 已提交
84
	if (tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
L
Linus Torvalds 已提交
85
			    &init->gate_addr))
J
Jeff Dike 已提交
86 87 88 89
		return 0;
	if (init->dev_name == NULL) {
		printk(KERN_ERR "ethertap_setup : Missing tap device name\n");
		return 0;
L
Linus Torvalds 已提交
90 91
	}

J
Jeff Dike 已提交
92
	return 1;
L
Linus Torvalds 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106
}

static struct transport ethertap_transport = {
	.list 		= LIST_HEAD_INIT(ethertap_transport.list),
	.name 		= "ethertap",
	.setup  	= ethertap_setup,
	.user 		= &ethertap_user_info,
	.kern 		= &ethertap_kern_info,
	.private_size 	= sizeof(struct ethertap_data),
};

static int register_ethertap(void)
{
	register_transport(&ethertap_transport);
107
	return 0;
L
Linus Torvalds 已提交
108 109
}

110
late_initcall(register_ethertap);