ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / um / drivers / daemon_user.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 <errno.h>
9 #include <unistd.h>
10 #include <stdint.h>
11 #include <sys/socket.h>
12 #include <sys/un.h>
13 #include <sys/time.h>
14 #include "net_user.h"
15 #include "daemon.h"
16 #include "kern_util.h"
17 #include "user_util.h"
18 #include "user.h"
19 #include "os.h"
20
21 #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
22
23 enum request_type { REQ_NEW_CONTROL };
24
25 #define SWITCH_MAGIC 0xfeedface
26
27 struct request_v3 {
28         uint32_t magic;
29         uint32_t version;
30         enum request_type type;
31         struct sockaddr_un sock;
32 };
33
34 static struct sockaddr_un *new_addr(void *name, int len)
35 {
36         struct sockaddr_un *sun;
37
38         sun = um_kmalloc(sizeof(struct sockaddr_un));
39         if(sun == NULL){
40                 printk("new_addr: allocation of sockaddr_un failed\n");
41                 return(NULL);
42         }
43         sun->sun_family = AF_UNIX;
44         memcpy(sun->sun_path, name, len);
45         return(sun);
46 }
47
48 static int connect_to_switch(struct daemon_data *pri)
49 {
50         struct sockaddr_un *ctl_addr = pri->ctl_addr;
51         struct sockaddr_un *local_addr = pri->local_addr;
52         struct sockaddr_un *sun;
53         struct request_v3 req;
54         int fd, n, err;
55
56         if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
57                 printk("daemon_open : control socket failed, errno = %d\n", 
58                        errno);          
59                 return(-errno);
60         }
61
62         if(connect(pri->control, (struct sockaddr *) ctl_addr, 
63                    sizeof(*ctl_addr)) < 0){
64                 printk("daemon_open : control connect failed, errno = %d\n",
65                        errno);
66                 err = -errno;
67                 goto out;
68         }
69
70         if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
71                 printk("daemon_open : data socket failed, errno = %d\n", 
72                        errno);
73                 err = -errno;
74                 goto out;
75         }
76         if(bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0){
77                 printk("daemon_open : data bind failed, errno = %d\n", 
78                        errno);
79                 err = -errno;
80                 goto out_close;
81         }
82
83         sun = um_kmalloc(sizeof(struct sockaddr_un));
84         if(sun == NULL){
85                 printk("new_addr: allocation of sockaddr_un failed\n");
86                 err = -ENOMEM;
87                 goto out_close;
88         }
89
90         req.magic = SWITCH_MAGIC;
91         req.version = SWITCH_VERSION;
92         req.type = REQ_NEW_CONTROL;
93         req.sock = *local_addr;
94         n = write(pri->control, &req, sizeof(req));
95         if(n != sizeof(req)){
96                 printk("daemon_open : control setup request returned %d, "
97                        "errno = %d\n", n, errno);
98                 err = -ENOTCONN;
99                 goto out;               
100         }
101
102         n = read(pri->control, sun, sizeof(*sun));
103         if(n != sizeof(*sun)){
104                 printk("daemon_open : read of data socket returned %d, "
105                        "errno = %d\n", n, errno);
106                 err = -ENOTCONN;
107                 goto out_close;         
108         }
109
110         pri->data_addr = sun;
111         return(fd);
112
113  out_close:
114         close(fd);
115  out:
116         close(pri->control);
117         return(err);
118 }
119
120 static void daemon_user_init(void *data, void *dev)
121 {
122         struct daemon_data *pri = data;
123         struct timeval tv;
124         struct {
125                 char zero;
126                 int pid;
127                 int usecs;
128         } name;
129
130         if(!strcmp(pri->sock_type, "unix"))
131                 pri->ctl_addr = new_addr(pri->ctl_sock, 
132                                          strlen(pri->ctl_sock) + 1);
133         name.zero = 0;
134         name.pid = os_getpid();
135         gettimeofday(&tv, NULL);
136         name.usecs = tv.tv_usec;
137         pri->local_addr = new_addr(&name, sizeof(name));
138         pri->dev = dev;
139         pri->fd = connect_to_switch(pri);
140         if(pri->fd < 0){
141                 kfree(pri->local_addr);
142                 pri->local_addr = NULL;
143         }
144 }
145
146 static int daemon_open(void *data)
147 {
148         struct daemon_data *pri = data;
149         return(pri->fd);
150 }
151
152 static void daemon_remove(void *data)
153 {
154         struct daemon_data *pri = data;
155
156         close(pri->fd);
157         close(pri->control);
158         if(pri->data_addr != NULL) kfree(pri->data_addr);
159         if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
160         if(pri->local_addr != NULL) kfree(pri->local_addr);
161 }
162
163 int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
164 {
165         struct sockaddr_un *data_addr = pri->data_addr;
166
167         return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
168 }
169
170 static int daemon_set_mtu(int mtu, void *data)
171 {
172         return(mtu);
173 }
174
175 struct net_user_info daemon_user_info = {
176         .init           = daemon_user_init,
177         .open           = daemon_open,
178         .close          = NULL,
179         .remove         = daemon_remove,
180         .set_mtu        = daemon_set_mtu,
181         .add_address    = NULL,
182         .delete_address = NULL,
183         .max_packet     = MAX_PACKET - ETH_HEADER_OTHER
184 };
185
186 /*
187  * Overrides for Emacs so that we follow Linus's tabbing style.
188  * Emacs will notice this stuff at the end of the file and automatically
189  * adjust the settings for this buffer only.  This must remain at the end
190  * of the file.
191  * ---------------------------------------------------------------------------
192  * Local variables:
193  * c-file-style: "linux"
194  * End:
195  */