+static const char *parse_host_addr(struct event *event)
+{
+ const char *val;
+
+ val = event_get_param(event, "tftp");
+ if (val)
+ return val;
+
+ val = event_get_param(event, "siaddr");
+ if (val)
+ return val;
+
+ val = event_get_param(event, "serverid");
+ if (val)
+ return val;
+
+ return NULL;
+}
+
+static char *parse_mac_addr(struct discover_context *ctx, const char *mac)
+{
+ unsigned int mac_addr_arr[MAC_ADDR_SIZE];
+ char *mac_addr;
+
+ sscanf(mac, "%X:%X:%X:%X:%X:%X", mac_addr_arr, mac_addr_arr + 1,
+ mac_addr_arr + 2, mac_addr_arr + 3, mac_addr_arr + 4,
+ mac_addr_arr + 5);
+
+ mac_addr = talloc_asprintf(ctx, "01-%02x-%02x-%02x-%02x-%02x-%02x",
+ mac_addr_arr[0], mac_addr_arr[1], mac_addr_arr[2],
+ mac_addr_arr[3], mac_addr_arr[4], mac_addr_arr[5]);
+
+ return mac_addr;
+}
+
+static char *parse_ip_addr(struct discover_context *ctx, const char *ip)
+{
+ unsigned int ip_addr_arr[IP_ADDR_SIZE];
+ char *ip_hex;
+
+ sscanf(ip, "%u.%u.%u.%u", ip_addr_arr, ip_addr_arr + 1,
+ ip_addr_arr + 2, ip_addr_arr + 3);
+
+ ip_hex = talloc_asprintf(ctx, "%02X%02X%02X%02X", ip_addr_arr[0],
+ ip_addr_arr[1], ip_addr_arr[2], ip_addr_arr[3]);
+
+ return ip_hex;
+}
+
+struct pb_url *user_event_parse_conf_url(struct discover_context *ctx,
+ struct event *event, bool *is_complete)
+{
+ const char *conffile, *pathprefix, *host, *bootfile, *bootfile_url;
+ char *p, *basedir, *url_str;
+ struct pb_url *url;
+
+ conffile = event_get_param(event, "pxeconffile");
+ pathprefix = event_get_param(event, "pxepathprefix");
+ bootfile = event_get_param(event, "bootfile");
+ bootfile_url = event_get_param(event, "bootfile_url");
+
+ /* If we're given a conf file, we're able to generate a complete URL to
+ * the configuration file, and the parser doesn't need to do any
+ * further autodiscovery */
+ *is_complete = !!conffile;
+
+ /* if conffile is a URL, that's all we need */
+ if (conffile && is_url(conffile)) {
+ url = pb_url_parse(ctx, conffile);
+ return url;
+ }
+
+ /* If we can create a URL from pathprefix (optionally with
+ * conffile appended to create a complete URL), use that */
+ if (pathprefix && is_url(pathprefix)) {
+ if (conffile) {
+ url_str = talloc_asprintf(ctx, "%s%s",
+ pathprefix, conffile);
+ url = pb_url_parse(ctx, url_str);
+ talloc_free(url_str);
+ } else {
+ url = pb_url_parse(ctx, pathprefix);
+ }
+
+ return url;
+ }
+
+ host = parse_host_addr(event);
+ if (!host) {
+ pb_log_fn("host address not found\n");
+
+ /* No full URLs and no host address? Check for DHCPv6 options */
+ if (bootfile_url && is_url(bootfile_url)) {
+ *is_complete = true;
+ return pb_url_parse(ctx, bootfile_url);
+ }
+ return NULL;
+ }
+
+ url_str = talloc_asprintf(ctx, "tftp://%s/", host);
+
+ /* if we have a pathprefix, use that directly.. */
+ if (pathprefix) {
+ /* strip leading slashes */
+ while (pathprefix[0] == '/')
+ pathprefix++;
+ url_str = talloc_asprintf_append(url_str, "%s", pathprefix);
+
+ /* ... otherwise, add a path based on the bootfile name, but only
+ * if conffile isn't an absolute path itself */
+ } else if (bootfile && !(conffile && conffile[0] == '/')) {
+
+ basedir = talloc_strdup(ctx, bootfile);
+
+ /* strip filename from the bootfile path, leaving only a
+ * directory */
+ p = strrchr(basedir, '/');
+ if (!p)
+ p = basedir;
+ *p = '\0';
+
+ if (strlen(basedir))
+ url_str = talloc_asprintf_append(url_str, "%s/",
+ basedir);
+
+ talloc_free(basedir);
+ }
+
+ /* finally, append conffile */
+ if (conffile)
+ url_str = talloc_asprintf_append(url_str, "%s", conffile);
+
+ url = pb_url_parse(ctx, url_str);
+
+ talloc_free(url_str);
+
+ return url;
+}
+
+char **user_event_parse_conf_filenames(
+ struct discover_context *ctx, struct event *event)
+{
+ char *mac_addr, *ip_hex;
+ const char *mac, *ip;
+ char **filenames;
+ int index, len;
+
+ mac = event_get_param(event, "mac");
+ if (mac)
+ mac_addr = parse_mac_addr(ctx, mac);
+ else
+ mac_addr = NULL;
+
+ ip = event_get_param(event, "ip");
+ if (ip) {
+ ip_hex = parse_ip_addr(ctx, ip);
+ len = strlen(ip_hex);
+ } else {
+ ip_hex = NULL;
+ len = 0;
+ }
+
+ if (!mac_addr && !ip_hex) {
+ pb_log_fn("neither mac nor ip parameter found\n");
+ return NULL;
+ }
+
+ /* Filenames as fallback IP's + mac + default */
+ filenames = talloc_array(ctx, char *, len + 3);
+
+ index = 0;
+ if (mac_addr)
+ filenames[index++] = talloc_strdup(filenames, mac_addr);
+
+ while (len) {
+ filenames[index++] = talloc_strdup(filenames, ip_hex);
+ ip_hex[--len] = '\0';
+ }
+
+ filenames[index++] = talloc_strdup(filenames, "default");
+ filenames[index++] = NULL;
+
+ if (mac_addr)
+ talloc_free(mac_addr);
+
+ if (ip_hex)
+ talloc_free(ip_hex);
+
+ return filenames;
+}
+
+static int user_event_dhcp(struct user_event *uev, struct event *event)