ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / um / os-Linux / drivers / ethertap_kern.c
1 /*
2  * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
3  * James Leu (jleu@mindspring.net).
4  * Copyright (C) 2001 by various other people who didn't put their name here.
5  * Licensed under the GPL.
6  */
7
8 #include "linux/init.h"
9 #include "linux/netdevice.h"
10 #include "linux/etherdevice.h"
11 #include "linux/init.h"
12 #include "net_kern.h"
13 #include "net_user.h"
14 #include "etap.h"
15
16 struct ethertap_init {
17         char *dev_name;
18         char *gate_addr;
19 };
20
21 static void etap_init(struct net_device *dev, void *data)
22 {
23         struct uml_net_private *pri;
24         struct ethertap_data *epri;
25         struct ethertap_init *init = data;
26
27         pri = dev->priv;
28         epri = (struct ethertap_data *) pri->user;
29         epri->dev_name = init->dev_name;
30         epri->gate_addr = init->gate_addr;
31         epri->data_fd = -1;
32         epri->control_fd = -1;
33         epri->dev = dev;
34
35         printk("ethertap backend - %s", epri->dev_name);
36         if (epri->gate_addr != NULL)
37                 printk(", IP = %s", epri->gate_addr);
38         printk("\n");
39 }
40
41 static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
42 {
43         int len;
44
45         *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
46         if(*skb == NULL) return(-ENOMEM);
47         len = net_recvfrom(fd, (*skb)->mac.raw, 
48                            (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
49         if(len <= 0) return(len);
50         skb_pull(*skb, 2);
51         len -= 2;
52         return(len);
53 }
54
55 static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
56 {
57         if(skb_headroom(*skb) < 2){
58                 struct sk_buff *skb2;
59
60                 skb2 = skb_realloc_headroom(*skb, 2);
61                 dev_kfree_skb(*skb);
62                 if (skb2 == NULL) return(-ENOMEM);
63                 *skb = skb2;
64         }
65         skb_push(*skb, 2);
66         return(net_send(fd, (*skb)->data, (*skb)->len));
67 }
68
69 struct net_kern_info ethertap_kern_info = {
70         .init                   = etap_init,
71         .protocol               = eth_protocol,
72         .read                   = etap_read,
73         .write                  = etap_write,
74 };
75
76 int ethertap_setup(char *str, char **mac_out, void *data)
77 {
78         struct ethertap_init *init = data;
79
80         *init = ((struct ethertap_init)
81                 { .dev_name     = NULL,
82                   .gate_addr    = NULL });
83         if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
84                             &init->gate_addr))
85                 return(0);
86         if(init->dev_name == NULL){
87                 printk("ethertap_setup : Missing tap device name\n");
88                 return(0);
89         }
90
91         return(1);
92 }
93
94 static struct transport ethertap_transport = {
95         .list           = LIST_HEAD_INIT(ethertap_transport.list),
96         .name           = "ethertap",
97         .setup          = ethertap_setup,
98         .user           = &ethertap_user_info,
99         .kern           = &ethertap_kern_info,
100         .private_size   = sizeof(struct ethertap_data),
101 };
102
103 static int register_ethertap(void)
104 {
105         register_transport(&ethertap_transport);
106         return(1);
107 }
108
109 __initcall(register_ethertap);
110
111 /*
112  * Overrides for Emacs so that we follow Linus's tabbing style.
113  * Emacs will notice this stuff at the end of the file and automatically
114  * adjust the settings for this buffer only.  This must remain at the end
115  * of the file.
116  * ---------------------------------------------------------------------------
117  * Local variables:
118  * c-file-style: "linux"
119  * End:
120  */