2 * Copyright (C) 2009 Sony Computer Entertainment Inc.
3 * Copyright 2009 Sony Corp.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #if defined(HAVE_CONFIG_H)
27 #include <sys/socket.h>
28 #include <sys/types.h>
33 #include <types/types.h>
34 #include <talloc/talloc.h>
35 #include <waiter/waiter.h>
37 #include "device-handler.h"
40 #include "user-event.h"
43 #define MAC_ADDR_SIZE 6
44 #define IP_ADDR_SIZE 4
47 struct device_handler *handler;
51 static const char *event_action_name(enum event_action action)
54 case EVENT_ACTION_ADD:
56 case EVENT_ACTION_REMOVE:
58 case EVENT_ACTION_DHCP:
67 static void user_event_print_event(struct event __attribute__((unused)) *event)
71 pb_debug("user_event %s event:\n", event_action_name(event->action));
72 pb_debug("\tdevice: %s\n", event->device);
74 for (i = 0; i < event->n_params; i++)
75 pb_debug("\t%-12s => %s\n",
76 event->params[i].name, event->params[i].value);
79 static struct resource *user_event_resource(struct discover_boot_option *opt,
82 const char *siaddr, *boot_file;
87 siaddr = event_get_param(event, "siaddr");
89 pb_log("%s: next server option not found\n", __func__);
93 boot_file = event_get_param(event, "boot_file");
95 pb_log("%s: boot_file not found\n", __func__);
99 url_str = talloc_asprintf(opt, "%s%s/%s", "tftp://", siaddr, boot_file);
100 url = pb_url_parse(opt, url_str);
101 talloc_free(url_str);
106 res = create_url_resource(opt, url);
115 static int parse_user_event(struct discover_context *ctx, struct event *event)
117 struct discover_boot_option *d_opt;
118 char *server_ip, *root_dir, *p;
119 struct boot_option *opt;
123 dev = ctx->device->device;
125 d_opt = discover_boot_option_create(ctx, ctx->device);
131 val = event_get_param(event, "name");
134 pb_log("%s: no name found\n", __func__);
138 opt->id = talloc_asprintf(opt, "%s#%s", dev->id, val);
139 opt->name = talloc_strdup(opt, val);
141 d_opt->boot_image = user_event_resource(d_opt, event);
142 if (!d_opt->boot_image) {
143 pb_log("%s: no boot image found for %s!\n", __func__,
148 val = event_get_param(event, "rootpath");
150 server_ip = talloc_strdup(opt, val);
151 p = strchr(server_ip, ':');
153 root_dir = talloc_strdup(opt, p + 1);
155 opt->boot_args = talloc_asprintf(opt, "%s%s:%s",
156 "root=/dev/nfs ip=any nfsroot=",
157 server_ip, root_dir);
159 talloc_free(root_dir);
161 opt->boot_args = talloc_asprintf(opt, "%s",
162 "root=/dev/nfs ip=any nfsroot=");
165 talloc_free(server_ip);
168 opt->description = talloc_asprintf(opt, "%s %s", opt->boot_image_file,
169 opt->boot_args ? : "");
171 if (event_get_param(event, "default"))
172 opt->is_default = true;
174 discover_context_add_boot_option(ctx, d_opt);
184 static const char *parse_host_addr(struct event *event)
188 val = event_get_param(event, "tftp");
192 val = event_get_param(event, "siaddr");
196 val = event_get_param(event, "serverid");
203 static char *parse_mac_addr(struct discover_context *ctx, const char *mac)
205 unsigned int mac_addr_arr[MAC_ADDR_SIZE];
208 sscanf(mac, "%X:%X:%X:%X:%X:%X", mac_addr_arr, mac_addr_arr + 1,
209 mac_addr_arr + 2, mac_addr_arr + 3, mac_addr_arr + 4,
212 mac_addr = talloc_asprintf(ctx, "01-%02X-%02X-%02X-%02X-%02X-%02X",
213 mac_addr_arr[0], mac_addr_arr[1], mac_addr_arr[2],
214 mac_addr_arr[3], mac_addr_arr[4], mac_addr_arr[5]);
219 static char *parse_ip_addr(struct discover_context *ctx, const char *ip)
221 unsigned int ip_addr_arr[IP_ADDR_SIZE];
224 sscanf(ip, "%u.%u.%u.%u", ip_addr_arr, ip_addr_arr + 1,
225 ip_addr_arr + 2, ip_addr_arr + 3);
227 ip_hex = talloc_asprintf(ctx, "%02X%02X%02X%02X", ip_addr_arr[0],
228 ip_addr_arr[1], ip_addr_arr[2], ip_addr_arr[3]);
233 struct pb_url *user_event_parse_conf_url(struct discover_context *ctx,
236 const char *conffile, *host, *bootfile;
237 char *p, *basedir, *url_str;
240 conffile = event_get_param(event, "conffile");
242 if (is_url(conffile)) {
243 url = pb_url_parse(ctx, conffile);
245 host = parse_host_addr(event);
247 pb_log("%s: host address not found\n",
252 url_str = talloc_asprintf(ctx, "%s%s/%s", "tftp://",
254 url = pb_url_parse(ctx, url_str);
256 talloc_free(url_str);
261 host = parse_host_addr(event);
263 pb_log("%s: host address not found\n", __func__);
267 bootfile = event_get_param(event, "bootfile");
269 pb_log("%s: bootfile param not found\n", __func__);
273 basedir = talloc_strdup(ctx, bootfile);
274 p = strchr(basedir, '/');
278 if (!strcmp(basedir,"") || !strcmp(basedir, "."))
279 url_str = talloc_asprintf(ctx, "%s%s/", "tftp://",host);
281 url_str = talloc_asprintf(ctx, "%s%s/%s/", "tftp://",host,
284 url = pb_url_parse(ctx, url_str);
286 talloc_free(url_str);
287 talloc_free(basedir);
293 char **user_event_parse_conf_filenames(
294 struct discover_context *ctx, struct event *event)
296 char *mac_addr, *ip_hex;
297 const char *mac, *ip;
301 mac = event_get_param(event, "mac");
303 mac_addr = parse_mac_addr(ctx, mac);
307 ip = event_get_param(event, "ip");
309 ip_hex = parse_ip_addr(ctx, ip);
310 len = strlen(ip_hex);
316 if (!mac_addr && !ip_hex) {
317 pb_log("%s: neither mac nor ip parameter found\n", __func__);
321 /* Filenames as fallback IP's + mac + default */
322 filenames = talloc_array(ctx, char *, len + 3);
326 filenames[index++] = talloc_strdup(filenames, mac_addr);
329 filenames[index++] = talloc_strdup(filenames, ip_hex);
330 ip_hex[--len] = '\0';
333 filenames[index++] = talloc_strdup(filenames, "default");
334 filenames[index++] = NULL;
337 talloc_free(mac_addr);
345 static int user_event_dhcp(struct user_event *uev, struct event *event)
347 struct device_handler *handler = uev->handler;
348 struct discover_device *dev;
350 dev = discover_device_create(handler, event->device);
352 device_handler_dhcp(handler, dev, event);
357 static int user_event_conf(struct user_event *uev, struct event *event)
359 struct device_handler *handler = uev->handler;
360 struct discover_device *dev;
364 val = event_get_param(event, "url");
368 url = pb_url_parse(event, val);
372 dev = discover_device_create(handler, event->device);
374 device_handler_conf(handler, dev, url);
379 static int user_event_add(struct user_event *uev, struct event *event)
381 struct device_handler *handler = uev->handler;
382 struct discover_context *ctx;
383 struct discover_device *dev;
385 dev = discover_device_create(handler, event->device);
386 ctx = device_handler_discover_context_create(handler, dev);
388 parse_user_event(ctx, event);
390 device_handler_discover_context_commit(handler, ctx);
397 static int user_event_remove(struct user_event *uev, struct event *event)
399 struct device_handler *handler = uev->handler;
400 struct discover_device *dev;
402 dev = device_lookup_by_id(handler, event->device);
406 device_handler_remove(handler, dev);
411 static void user_event_handle_message(struct user_event *uev, char *buf,
417 event = talloc(uev, struct event);
418 event->type = EVENT_TYPE_USER;
420 result = event_parse_ad_message(event, buf, len);
425 user_event_print_event(event);
427 switch (event->action) {
428 case EVENT_ACTION_ADD:
429 result = user_event_add(uev, event);
431 case EVENT_ACTION_REMOVE:
432 result = user_event_remove(uev, event);
434 case EVENT_ACTION_CONF:
435 result = user_event_conf(uev, event);
437 case EVENT_ACTION_DHCP:
438 result = user_event_dhcp(uev, event);
449 static int user_event_process(void *arg)
451 struct user_event *uev = arg;
452 char buf[PBOOT_USER_EVENT_SIZE];
455 len = recvfrom(uev->socket, buf, sizeof(buf), 0, NULL, NULL);
458 pb_log("%s: socket read failed: %s", __func__, strerror(errno));
463 pb_log("%s: empty", __func__);
467 pb_debug("%s: %u bytes\n", __func__, len);
469 user_event_handle_message(uev, buf, len);
474 static int user_event_destructor(void *arg)
476 struct user_event *uev = arg;
478 pb_debug("%s\n", __func__);
480 if (uev->socket >= 0)
486 struct user_event *user_event_init(struct waitset *waitset,
487 struct device_handler *handler)
489 struct sockaddr_un addr;
490 struct user_event *uev;
492 unlink(PBOOT_USER_EVENT_SOCKET);
494 uev = talloc(NULL, struct user_event);
496 uev->handler = handler;
498 uev->socket = socket(AF_UNIX, SOCK_DGRAM, 0);
499 if (uev->socket < 0) {
500 pb_log("%s: Error creating event handler socket: %s\n",
501 __func__, strerror(errno));
505 talloc_set_destructor(uev, user_event_destructor);
507 memset(&addr, 0, sizeof(addr));
508 addr.sun_family = AF_UNIX;
509 strcpy(addr.sun_path, PBOOT_USER_EVENT_SOCKET);
511 if (bind(uev->socket, (struct sockaddr *)&addr, sizeof(addr))) {
512 pb_log("Error binding event handler socket: %s\n",
516 waiter_register_io(waitset, uev->socket, WAIT_IN,
517 user_event_process, uev);
519 pb_debug("%s: waiting on %s\n", __func__, PBOOT_USER_EVENT_SOCKET);
528 void user_event_destroy(struct user_event *uev)