int parse_option_decl(FILE *cfile, struct option_data *options) { char *val; int token; u_int8_t buf[4]; u_int8_t hunkbuf[1024]; int hunkix = 0; char *fmt; struct iaddr ip_addr; u_int8_t *dp; int len, code; int nul_term = 0; token = next_token(&val, cfile); if (!is_identifier(token)) { parse_warn("expecting identifier after option keyword."); if (token != ';') skip_to_semi(cfile); return (-1); } /* Look up the actual option info. */ fmt = NULL; for (code = 0; code < 256; code++) if (strcmp(dhcp_options[code].name, val) == 0) break; if (code > 255) { parse_warn("no option named %s", val); skip_to_semi(cfile); return (-1); } /* Parse the option data... */ do { for (fmt = dhcp_options[code].format; *fmt; fmt++) { if (*fmt == 'A') break; switch (*fmt) { case 'X': len = parse_X(cfile, &hunkbuf[hunkix], sizeof(hunkbuf) - hunkix); hunkix += len; break; case 't': /* Text string... */ token = next_token(&val, cfile); if (token != TOK_STRING) { parse_warn("expecting string."); skip_to_semi(cfile); return (-1); } len = strlen(val); if (hunkix + len + 1 > sizeof(hunkbuf)) { parse_warn("option data buffer %s", "overflow"); skip_to_semi(cfile); return (-1); } memcpy(&hunkbuf[hunkix], val, len + 1); nul_term = 1; hunkix += len; break; case 'I': /* IP address. */ if (!parse_ip_addr(cfile, &ip_addr)) return (-1); len = ip_addr.len; dp = ip_addr.iabuf; alloc: if (hunkix + len > sizeof(hunkbuf)) { parse_warn("option data buffer " "overflow"); skip_to_semi(cfile); return (-1); } memcpy(&hunkbuf[hunkix], dp, len); hunkix += len; break; case 'L': /* Unsigned 32-bit integer... */ case 'l': /* Signed 32-bit integer... */ token = next_token(&val, cfile); if (token != TOK_NUMBER) { need_number: parse_warn("expecting number."); if (token != ';') skip_to_semi(cfile); return (-1); } convert_num(buf, val, 0, 32); len = 4; dp = buf; goto alloc; case 's': /* Signed 16-bit integer. */ case 'S': /* Unsigned 16-bit integer. */ token = next_token(&val, cfile); if (token != TOK_NUMBER) goto need_number; convert_num(buf, val, 0, 16); len = 2; dp = buf; goto alloc; case 'b': /* Signed 8-bit integer. */ case 'B': /* Unsigned 8-bit integer. */ token = next_token(&val, cfile); if (token != TOK_NUMBER) goto need_number; convert_num(buf, val, 0, 8); len = 1; dp = buf; goto alloc; case 'f': /* Boolean flag. */ token = next_token(&val, cfile); if (!is_identifier(token)) { parse_warn("expecting identifier."); bad_flag: if (token != ';') skip_to_semi(cfile); return (-1); } if (!strcasecmp(val, "true") || !strcasecmp(val, "on")) buf[0] = 1; else if (!strcasecmp(val, "false") || !strcasecmp(val, "off")) buf[0] = 0; else { parse_warn("expecting boolean."); goto bad_flag; } len = 1; dp = buf; goto alloc; default: warning("Bad format %c in parse_option_param.", *fmt); skip_to_semi(cfile); return (-1); } } token = next_token(&val, cfile); } while (*fmt == 'A' && token == ','); if (token != ';') { parse_warn("semicolon expected."); skip_to_semi(cfile); return (-1); } options[code].data = malloc(hunkix + nul_term); if (!options[code].data) error("out of memory allocating option data."); memcpy(options[code].data, hunkbuf, hunkix + nul_term); options[code].len = hunkix; return (code); }
struct option * parse_option_decl(FILE *cfile, struct option_data *options) { char *val; int token; u_int8_t buf[4]; u_int8_t hunkbuf[1024]; int hunkix = 0; char *vendor; char *fmt; struct universe *universe; struct option *option; struct iaddr ip_addr; u_int8_t *dp; int len; int nul_term = 0; token = next_token(&val, cfile); if (!is_identifier(token)) { parse_warn("expecting identifier after option keyword."); if (token != SEMI) skip_to_semi(cfile); return (NULL); } if ((vendor = strdup(val)) == NULL) error("no memory for vendor information."); token = peek_token(&val, cfile); if (token == DOT) { /* Go ahead and take the DOT token... */ token = next_token(&val, cfile); /* The next token should be an identifier... */ token = next_token(&val, cfile); if (!is_identifier(token)) { parse_warn("expecting identifier after '.'"); if (token != SEMI) skip_to_semi(cfile); return (NULL); } /* Look up the option name hash table for the specified vendor. */ universe = ((struct universe *)hash_lookup(&universe_hash, (unsigned char *)vendor, 0)); /* If it's not there, we can't parse the rest of the declaration. */ if (!universe) { parse_warn("no vendor named %s.", vendor); skip_to_semi(cfile); return (NULL); } } else { /* Use the default hash table, which contains all the standard dhcp option names. */ val = vendor; universe = &dhcp_universe; } /* Look up the actual option info... */ option = (struct option *)hash_lookup(universe->hash, (unsigned char *)val, 0); /* If we didn't get an option structure, it's an undefined option. */ if (!option) { if (val == vendor) parse_warn("no option named %s", val); else parse_warn("no option named %s for vendor %s", val, vendor); skip_to_semi(cfile); return (NULL); } /* Free the initial identifier token. */ free(vendor); /* Parse the option data... */ do { for (fmt = option->format; *fmt; fmt++) { if (*fmt == 'A') break; switch (*fmt) { case 'X': len = parse_X(cfile, &hunkbuf[hunkix], sizeof(hunkbuf) - hunkix); hunkix += len; break; case 't': /* Text string... */ token = next_token(&val, cfile); if (token != STRING) { parse_warn("expecting string."); skip_to_semi(cfile); return (NULL); } len = strlen(val); if (hunkix + len + 1 > sizeof(hunkbuf)) { parse_warn("option data buffer %s", "overflow"); skip_to_semi(cfile); return (NULL); } memcpy(&hunkbuf[hunkix], val, len + 1); nul_term = 1; hunkix += len; break; case 'I': /* IP address. */ if (!parse_ip_addr(cfile, &ip_addr)) return (NULL); len = ip_addr.len; dp = ip_addr.iabuf; alloc: if (hunkix + len > sizeof(hunkbuf)) { parse_warn("option data buffer " "overflow"); skip_to_semi(cfile); return (NULL); } memcpy(&hunkbuf[hunkix], dp, len); hunkix += len; break; case 'L': /* Unsigned 32-bit integer... */ case 'l': /* Signed 32-bit integer... */ token = next_token(&val, cfile); if (token != NUMBER) { need_number: parse_warn("expecting number."); if (token != SEMI) skip_to_semi(cfile); return (NULL); } convert_num(buf, val, 0, 32); len = 4; dp = buf; goto alloc; case 's': /* Signed 16-bit integer. */ case 'S': /* Unsigned 16-bit integer. */ token = next_token(&val, cfile); if (token != NUMBER) goto need_number; convert_num(buf, val, 0, 16); len = 2; dp = buf; goto alloc; case 'b': /* Signed 8-bit integer. */ case 'B': /* Unsigned 8-bit integer. */ token = next_token(&val, cfile); if (token != NUMBER) goto need_number; convert_num(buf, val, 0, 8); len = 1; dp = buf; goto alloc; case 'f': /* Boolean flag. */ token = next_token(&val, cfile); if (!is_identifier(token)) { parse_warn("expecting identifier."); bad_flag: if (token != SEMI) skip_to_semi(cfile); return (NULL); } if (!strcasecmp(val, "true") || !strcasecmp(val, "on")) buf[0] = 1; else if (!strcasecmp(val, "false") || !strcasecmp(val, "off")) buf[0] = 0; else { parse_warn("expecting boolean."); goto bad_flag; } len = 1; dp = buf; goto alloc; default: warning("Bad format %c in parse_option_param.", *fmt); skip_to_semi(cfile); return (NULL); } } token = next_token(&val, cfile); } while (*fmt == 'A' && token == COMMA); if (token != SEMI) { parse_warn("semicolon expected."); skip_to_semi(cfile); return (NULL); } options[option->code].data = malloc(hunkix + nul_term); if (!options[option->code].data) error("out of memory allocating option data."); memcpy(options[option->code].data, hunkbuf, hunkix + nul_term); options[option->code].len = hunkix; return (option); }