01547e1f10bcff41281deb399aed39a42dfe47ef
[strongswan.git] / src / dumm / mconsole.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2001-2004 Jeff Dike
5 *
6 * Based on the "uml_mconsole" utility from Jeff Dike.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <sys/socket.h>
23 #include <errno.h>
24 #include <sys/un.h>
25
26 #include <debug.h>
27
28 #include "mconsole.h"
29
30 #define MCONSOLE_MAGIC 0xcafebabe
31 #define MCONSOLE_VERSION 2
32 #define MCONSOLE_MAX_DATA 512
33
34 typedef struct private_mconsole_t private_mconsole_t;
35
36 struct private_mconsole_t {
37 /** public interface */
38 mconsole_t public;
39 /** mconsole socket */
40 int console;
41 /** notify socket */
42 int notify;
43 /** address of uml socket */
44 struct sockaddr_un uml;
45 };
46
47 /**
48 * mconsole message format from "arch/um/include/mconsole.h"
49 */
50 typedef struct mconsole_request mconsole_request;
51 /** mconsole request message */
52 struct mconsole_request {
53 u_int32_t magic;
54 u_int32_t version;
55 u_int32_t len;
56 char data[MCONSOLE_MAX_DATA];
57 };
58
59
60 typedef struct mconsole_reply mconsole_reply;
61 /** mconsole reply message */
62 struct mconsole_reply {
63 u_int32_t err;
64 u_int32_t more;
65 u_int32_t len;
66 char data[MCONSOLE_MAX_DATA];
67 };
68
69 typedef struct mconsole_notify mconsole_notify;
70 /** mconsole notify message */
71 struct mconsole_notify {
72 u_int32_t magic;
73 u_int32_t version;
74 enum {
75 MCONSOLE_SOCKET,
76 MCONSOLE_PANIC,
77 MCONSOLE_HANG,
78 MCONSOLE_USER_NOTIFY,
79 } type;
80 u_int32_t len;
81 char data[MCONSOLE_MAX_DATA];
82 };
83
84 /**
85 * send a request to UML using mconsole
86 */
87 static bool request(private_mconsole_t *this, char *command)
88 {
89 mconsole_request request;
90 mconsole_reply reply;
91 bool first = TRUE, good = TRUE;
92 int len;
93
94 memset(&request, 0, sizeof(request));
95 request.magic = MCONSOLE_MAGIC;
96 request.version = MCONSOLE_VERSION;
97 request.len = min(strlen(command), sizeof(reply.data) - 1);
98 strncpy(request.data, command, request.len);
99
100 if (sendto(this->console, &request, sizeof(request), 0,
101 (struct sockaddr*)&this->uml, sizeof(this->uml)) < 0)
102 {
103 DBG1("sending mconsole command to UML failed: %m");
104 return FALSE;
105 }
106 do
107 {
108 len = recvfrom(this->console, &reply, sizeof(reply), 0, NULL, 0);
109 if (len < 0)
110 {
111 DBG1("receiving from mconsole failed: %m");
112 return FALSE;
113 }
114 if (first && reply.err)
115 {
116 good = FALSE;
117 DBG1("received error from UML mconsole: %s", reply.data);
118 }
119 first = FALSE;
120 }
121 while (reply.more);
122 return good;
123 }
124
125 /**
126 * Implementation of mconsole_t.add_iface.
127 */
128 static bool add_iface(private_mconsole_t *this, char *guest, char *host)
129 {
130 char buf[128];
131 int len;
132
133 len = snprintf(buf, sizeof(buf), "config %s=tuntap,%s", guest, host);
134 if (len < 0 || len >= sizeof(buf))
135 {
136 return FALSE;
137 }
138 return request(this, buf);
139 }
140
141 /**
142 * Implementation of mconsole_t.del_iface.
143 */
144 static bool del_iface(private_mconsole_t *this, char *guest)
145 {
146 char buf[128];
147 int len;
148
149 len = snprintf(buf, sizeof(buf), "remove %s", guest);
150 if (len < 0 || len >= sizeof(buf))
151 {
152 return FALSE;
153 }
154 return request(this, buf);
155 }
156
157 /**
158 * Implementation of mconsole_t.destroy.
159 */
160 static void destroy(private_mconsole_t *this)
161 {
162 close(this->console);
163 close(this->notify);
164 free(this);
165 }
166
167 /**
168 * setup the mconsole notify connection and wait for its readyness
169 */
170 static bool wait_for_notify(private_mconsole_t *this, char *nsock)
171 {
172 struct sockaddr_un addr;
173 mconsole_notify notify;
174 int len;
175
176 this->notify = socket(AF_UNIX, SOCK_DGRAM, 0);
177 if (this->notify < 0)
178 {
179 DBG1("opening mconsole notify socket failed: %m");
180 return FALSE;
181 }
182 memset(&addr, 0, sizeof(addr));
183 addr.sun_family = AF_UNIX;
184 strncpy(addr.sun_path, nsock, sizeof(addr));
185 if (bind(this->notify, (struct sockaddr*)&addr, sizeof(addr)) < 0)
186 {
187 DBG1("binding mconsole notify socket to '%s' failed: %m", nsock);
188 close(this->notify);
189 return FALSE;
190 }
191 do
192 {
193 len = recvfrom(this->notify, &notify, sizeof(notify), 0, NULL, 0);
194 } while (len < 0 && errno == EINTR);
195 if (len < 0 || len >= sizeof(notify))
196 {
197 DBG1("reading from mconsole notify socket failed: %m");
198 close(this->notify);
199 unlink(nsock);
200 return FALSE;
201 }
202 if (notify.magic != MCONSOLE_MAGIC ||
203 notify.version != MCONSOLE_VERSION ||
204 notify.type != MCONSOLE_SOCKET)
205 {
206 DBG1("received unexpected message from mconsole notify socket: %b",
207 &notify, sizeof(notify));
208 close(this->notify);
209 unlink(nsock);
210 return FALSE;
211 }
212 memset(&this->uml, 0, sizeof(this->uml));
213 this->uml.sun_family = AF_UNIX;
214 strncpy(this->uml.sun_path, (char*)&notify.data, sizeof(this->uml.sun_path));
215 return TRUE;
216 }
217
218 /**
219 * setup the mconsole console connection
220 */
221 static bool setup_console(private_mconsole_t *this)
222 {
223 struct sockaddr_un addr;
224
225 this->console = socket(AF_UNIX, SOCK_DGRAM, 0);
226 if (this->console < 0)
227 {
228 DBG1("opening mconsole socket failed: %m");
229 return FALSE;
230 }
231 memset(&addr, 0, sizeof(addr));
232 addr.sun_family = AF_UNIX;
233 snprintf(&addr.sun_path[1], sizeof(addr.sun_path), "%5d-%d",
234 getpid(), this->console);
235 if (bind(this->console, (struct sockaddr*)&addr, sizeof(addr)) < 0)
236 {
237 DBG1("binding mconsole socket to '%s' failed: %m", &addr.sun_path[1]);
238 close(this->console);
239 return FALSE;
240 }
241 return TRUE;
242 }
243
244 /**
245 * create the mconsole instance
246 */
247 mconsole_t *mconsole_create(char *notify)
248 {
249 private_mconsole_t *this = malloc_thing(private_mconsole_t);
250
251 this->public.add_iface = (bool(*)(mconsole_t*, char *guest, char *host))add_iface;
252 this->public.del_iface = (bool(*)(mconsole_t*, char *guest))del_iface;
253 this->public.destroy = (void*)destroy;
254
255 if (!wait_for_notify(this, notify))
256 {
257 free(this);
258 return NULL;
259 }
260
261 if (!setup_console(this))
262 {
263 close(this->notify);
264 unlink(notify);
265 free(this);
266 return NULL;
267 }
268 unlink(notify);
269
270 return &this->public;
271 }
272