1214503Srpaulo/* 2214503Srpaulo * hostapd / Configuration file parser 3252726Srpaulo * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> 4214503Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214503Srpaulo */ 8214503Srpaulo 9214503Srpaulo#include "utils/includes.h" 10214503Srpaulo#ifndef CONFIG_NATIVE_WINDOWS 11214503Srpaulo#include <grp.h> 12214503Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */ 13214503Srpaulo 14214503Srpaulo#include "utils/common.h" 15214503Srpaulo#include "utils/uuid.h" 16214503Srpaulo#include "common/ieee802_11_defs.h" 17214503Srpaulo#include "drivers/driver.h" 18214503Srpaulo#include "eap_server/eap.h" 19214503Srpaulo#include "radius/radius_client.h" 20214503Srpaulo#include "ap/wpa_auth.h" 21214503Srpaulo#include "ap/ap_config.h" 22214503Srpaulo#include "config_file.h" 23214503Srpaulo 24214503Srpaulo 25214503Srpauloextern struct wpa_driver_ops *wpa_drivers[]; 26214503Srpaulo 27214503Srpaulo 28214503Srpaulo#ifndef CONFIG_NO_VLAN 29214503Srpaulostatic int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, 30214503Srpaulo const char *fname) 31214503Srpaulo{ 32214503Srpaulo FILE *f; 33214503Srpaulo char buf[128], *pos, *pos2; 34214503Srpaulo int line = 0, vlan_id; 35214503Srpaulo struct hostapd_vlan *vlan; 36214503Srpaulo 37214503Srpaulo f = fopen(fname, "r"); 38214503Srpaulo if (!f) { 39214503Srpaulo wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname); 40214503Srpaulo return -1; 41214503Srpaulo } 42214503Srpaulo 43214503Srpaulo while (fgets(buf, sizeof(buf), f)) { 44214503Srpaulo line++; 45214503Srpaulo 46214503Srpaulo if (buf[0] == '#') 47214503Srpaulo continue; 48214503Srpaulo pos = buf; 49214503Srpaulo while (*pos != '\0') { 50214503Srpaulo if (*pos == '\n') { 51214503Srpaulo *pos = '\0'; 52214503Srpaulo break; 53214503Srpaulo } 54214503Srpaulo pos++; 55214503Srpaulo } 56214503Srpaulo if (buf[0] == '\0') 57214503Srpaulo continue; 58214503Srpaulo 59214503Srpaulo if (buf[0] == '*') { 60214503Srpaulo vlan_id = VLAN_ID_WILDCARD; 61214503Srpaulo pos = buf + 1; 62214503Srpaulo } else { 63214503Srpaulo vlan_id = strtol(buf, &pos, 10); 64214503Srpaulo if (buf == pos || vlan_id < 1 || 65214503Srpaulo vlan_id > MAX_VLAN_ID) { 66214503Srpaulo wpa_printf(MSG_ERROR, "Invalid VLAN ID at " 67214503Srpaulo "line %d in '%s'", line, fname); 68214503Srpaulo fclose(f); 69214503Srpaulo return -1; 70214503Srpaulo } 71214503Srpaulo } 72214503Srpaulo 73214503Srpaulo while (*pos == ' ' || *pos == '\t') 74214503Srpaulo pos++; 75214503Srpaulo pos2 = pos; 76214503Srpaulo while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0') 77214503Srpaulo pos2++; 78214503Srpaulo *pos2 = '\0'; 79214503Srpaulo if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) { 80214503Srpaulo wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d " 81214503Srpaulo "in '%s'", line, fname); 82214503Srpaulo fclose(f); 83214503Srpaulo return -1; 84214503Srpaulo } 85214503Srpaulo 86214503Srpaulo vlan = os_malloc(sizeof(*vlan)); 87214503Srpaulo if (vlan == NULL) { 88214503Srpaulo wpa_printf(MSG_ERROR, "Out of memory while reading " 89214503Srpaulo "VLAN interfaces from '%s'", fname); 90214503Srpaulo fclose(f); 91214503Srpaulo return -1; 92214503Srpaulo } 93214503Srpaulo 94214503Srpaulo os_memset(vlan, 0, sizeof(*vlan)); 95214503Srpaulo vlan->vlan_id = vlan_id; 96214503Srpaulo os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname)); 97214503Srpaulo if (bss->vlan_tail) 98214503Srpaulo bss->vlan_tail->next = vlan; 99214503Srpaulo else 100214503Srpaulo bss->vlan = vlan; 101214503Srpaulo bss->vlan_tail = vlan; 102214503Srpaulo } 103214503Srpaulo 104214503Srpaulo fclose(f); 105214503Srpaulo 106214503Srpaulo return 0; 107214503Srpaulo} 108214503Srpaulo#endif /* CONFIG_NO_VLAN */ 109214503Srpaulo 110214503Srpaulo 111214503Srpaulostatic int hostapd_acl_comp(const void *a, const void *b) 112214503Srpaulo{ 113214503Srpaulo const struct mac_acl_entry *aa = a; 114214503Srpaulo const struct mac_acl_entry *bb = b; 115214503Srpaulo return os_memcmp(aa->addr, bb->addr, sizeof(macaddr)); 116214503Srpaulo} 117214503Srpaulo 118214503Srpaulo 119214503Srpaulostatic int hostapd_config_read_maclist(const char *fname, 120214503Srpaulo struct mac_acl_entry **acl, int *num) 121214503Srpaulo{ 122214503Srpaulo FILE *f; 123214503Srpaulo char buf[128], *pos; 124214503Srpaulo int line = 0; 125214503Srpaulo u8 addr[ETH_ALEN]; 126214503Srpaulo struct mac_acl_entry *newacl; 127214503Srpaulo int vlan_id; 128214503Srpaulo 129214503Srpaulo if (!fname) 130214503Srpaulo return 0; 131214503Srpaulo 132214503Srpaulo f = fopen(fname, "r"); 133214503Srpaulo if (!f) { 134214503Srpaulo wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname); 135214503Srpaulo return -1; 136214503Srpaulo } 137214503Srpaulo 138214503Srpaulo while (fgets(buf, sizeof(buf), f)) { 139214503Srpaulo line++; 140214503Srpaulo 141214503Srpaulo if (buf[0] == '#') 142214503Srpaulo continue; 143214503Srpaulo pos = buf; 144214503Srpaulo while (*pos != '\0') { 145214503Srpaulo if (*pos == '\n') { 146214503Srpaulo *pos = '\0'; 147214503Srpaulo break; 148214503Srpaulo } 149214503Srpaulo pos++; 150214503Srpaulo } 151214503Srpaulo if (buf[0] == '\0') 152214503Srpaulo continue; 153214503Srpaulo 154214503Srpaulo if (hwaddr_aton(buf, addr)) { 155214503Srpaulo wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at " 156214503Srpaulo "line %d in '%s'", buf, line, fname); 157214503Srpaulo fclose(f); 158214503Srpaulo return -1; 159214503Srpaulo } 160214503Srpaulo 161214503Srpaulo vlan_id = 0; 162214503Srpaulo pos = buf; 163214503Srpaulo while (*pos != '\0' && *pos != ' ' && *pos != '\t') 164214503Srpaulo pos++; 165214503Srpaulo while (*pos == ' ' || *pos == '\t') 166214503Srpaulo pos++; 167214503Srpaulo if (*pos != '\0') 168214503Srpaulo vlan_id = atoi(pos); 169214503Srpaulo 170252726Srpaulo newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl)); 171214503Srpaulo if (newacl == NULL) { 172214503Srpaulo wpa_printf(MSG_ERROR, "MAC list reallocation failed"); 173214503Srpaulo fclose(f); 174214503Srpaulo return -1; 175214503Srpaulo } 176214503Srpaulo 177214503Srpaulo *acl = newacl; 178214503Srpaulo os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); 179214503Srpaulo (*acl)[*num].vlan_id = vlan_id; 180214503Srpaulo (*num)++; 181214503Srpaulo } 182214503Srpaulo 183214503Srpaulo fclose(f); 184214503Srpaulo 185214503Srpaulo qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); 186214503Srpaulo 187214503Srpaulo return 0; 188214503Srpaulo} 189214503Srpaulo 190214503Srpaulo 191214503Srpaulo#ifdef EAP_SERVER 192214503Srpaulostatic int hostapd_config_read_eap_user(const char *fname, 193214503Srpaulo struct hostapd_bss_config *conf) 194214503Srpaulo{ 195214503Srpaulo FILE *f; 196214503Srpaulo char buf[512], *pos, *start, *pos2; 197214503Srpaulo int line = 0, ret = 0, num_methods; 198214503Srpaulo struct hostapd_eap_user *user, *tail = NULL; 199214503Srpaulo 200214503Srpaulo if (!fname) 201214503Srpaulo return 0; 202214503Srpaulo 203252726Srpaulo if (os_strncmp(fname, "sqlite:", 7) == 0) { 204252726Srpaulo os_free(conf->eap_user_sqlite); 205252726Srpaulo conf->eap_user_sqlite = os_strdup(fname + 7); 206252726Srpaulo return 0; 207252726Srpaulo } 208252726Srpaulo 209214503Srpaulo f = fopen(fname, "r"); 210214503Srpaulo if (!f) { 211214503Srpaulo wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname); 212214503Srpaulo return -1; 213214503Srpaulo } 214214503Srpaulo 215214503Srpaulo /* Lines: "user" METHOD,METHOD2 "password" (password optional) */ 216214503Srpaulo while (fgets(buf, sizeof(buf), f)) { 217214503Srpaulo line++; 218214503Srpaulo 219214503Srpaulo if (buf[0] == '#') 220214503Srpaulo continue; 221214503Srpaulo pos = buf; 222214503Srpaulo while (*pos != '\0') { 223214503Srpaulo if (*pos == '\n') { 224214503Srpaulo *pos = '\0'; 225214503Srpaulo break; 226214503Srpaulo } 227214503Srpaulo pos++; 228214503Srpaulo } 229214503Srpaulo if (buf[0] == '\0') 230214503Srpaulo continue; 231214503Srpaulo 232214503Srpaulo user = NULL; 233214503Srpaulo 234214503Srpaulo if (buf[0] != '"' && buf[0] != '*') { 235214503Srpaulo wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in " 236214503Srpaulo "start) on line %d in '%s'", line, fname); 237214503Srpaulo goto failed; 238214503Srpaulo } 239214503Srpaulo 240214503Srpaulo user = os_zalloc(sizeof(*user)); 241214503Srpaulo if (user == NULL) { 242214503Srpaulo wpa_printf(MSG_ERROR, "EAP user allocation failed"); 243214503Srpaulo goto failed; 244214503Srpaulo } 245214503Srpaulo user->force_version = -1; 246214503Srpaulo 247214503Srpaulo if (buf[0] == '*') { 248214503Srpaulo pos = buf; 249214503Srpaulo } else { 250214503Srpaulo pos = buf + 1; 251214503Srpaulo start = pos; 252214503Srpaulo while (*pos != '"' && *pos != '\0') 253214503Srpaulo pos++; 254214503Srpaulo if (*pos == '\0') { 255214503Srpaulo wpa_printf(MSG_ERROR, "Invalid EAP identity " 256214503Srpaulo "(no \" in end) on line %d in '%s'", 257214503Srpaulo line, fname); 258214503Srpaulo goto failed; 259214503Srpaulo } 260214503Srpaulo 261214503Srpaulo user->identity = os_malloc(pos - start); 262214503Srpaulo if (user->identity == NULL) { 263214503Srpaulo wpa_printf(MSG_ERROR, "Failed to allocate " 264214503Srpaulo "memory for EAP identity"); 265214503Srpaulo goto failed; 266214503Srpaulo } 267214503Srpaulo os_memcpy(user->identity, start, pos - start); 268214503Srpaulo user->identity_len = pos - start; 269214503Srpaulo 270214503Srpaulo if (pos[0] == '"' && pos[1] == '*') { 271214503Srpaulo user->wildcard_prefix = 1; 272214503Srpaulo pos++; 273214503Srpaulo } 274214503Srpaulo } 275214503Srpaulo pos++; 276214503Srpaulo while (*pos == ' ' || *pos == '\t') 277214503Srpaulo pos++; 278214503Srpaulo 279214503Srpaulo if (*pos == '\0') { 280214503Srpaulo wpa_printf(MSG_ERROR, "No EAP method on line %d in " 281214503Srpaulo "'%s'", line, fname); 282214503Srpaulo goto failed; 283214503Srpaulo } 284214503Srpaulo 285214503Srpaulo start = pos; 286214503Srpaulo while (*pos != ' ' && *pos != '\t' && *pos != '\0') 287214503Srpaulo pos++; 288214503Srpaulo if (*pos == '\0') { 289214503Srpaulo pos = NULL; 290214503Srpaulo } else { 291214503Srpaulo *pos = '\0'; 292214503Srpaulo pos++; 293214503Srpaulo } 294214503Srpaulo num_methods = 0; 295214503Srpaulo while (*start) { 296214503Srpaulo char *pos3 = os_strchr(start, ','); 297214503Srpaulo if (pos3) { 298214503Srpaulo *pos3++ = '\0'; 299214503Srpaulo } 300214503Srpaulo user->methods[num_methods].method = 301214503Srpaulo eap_server_get_type( 302214503Srpaulo start, 303214503Srpaulo &user->methods[num_methods].vendor); 304214503Srpaulo if (user->methods[num_methods].vendor == 305214503Srpaulo EAP_VENDOR_IETF && 306214503Srpaulo user->methods[num_methods].method == EAP_TYPE_NONE) 307214503Srpaulo { 308214503Srpaulo if (os_strcmp(start, "TTLS-PAP") == 0) { 309214503Srpaulo user->ttls_auth |= EAP_TTLS_AUTH_PAP; 310214503Srpaulo goto skip_eap; 311214503Srpaulo } 312214503Srpaulo if (os_strcmp(start, "TTLS-CHAP") == 0) { 313214503Srpaulo user->ttls_auth |= EAP_TTLS_AUTH_CHAP; 314214503Srpaulo goto skip_eap; 315214503Srpaulo } 316214503Srpaulo if (os_strcmp(start, "TTLS-MSCHAP") == 0) { 317214503Srpaulo user->ttls_auth |= 318214503Srpaulo EAP_TTLS_AUTH_MSCHAP; 319214503Srpaulo goto skip_eap; 320214503Srpaulo } 321214503Srpaulo if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) { 322214503Srpaulo user->ttls_auth |= 323214503Srpaulo EAP_TTLS_AUTH_MSCHAPV2; 324214503Srpaulo goto skip_eap; 325214503Srpaulo } 326214503Srpaulo wpa_printf(MSG_ERROR, "Unsupported EAP type " 327214503Srpaulo "'%s' on line %d in '%s'", 328214503Srpaulo start, line, fname); 329214503Srpaulo goto failed; 330214503Srpaulo } 331214503Srpaulo 332214503Srpaulo num_methods++; 333252726Srpaulo if (num_methods >= EAP_MAX_METHODS) 334214503Srpaulo break; 335214503Srpaulo skip_eap: 336214503Srpaulo if (pos3 == NULL) 337214503Srpaulo break; 338214503Srpaulo start = pos3; 339214503Srpaulo } 340214503Srpaulo if (num_methods == 0 && user->ttls_auth == 0) { 341214503Srpaulo wpa_printf(MSG_ERROR, "No EAP types configured on " 342214503Srpaulo "line %d in '%s'", line, fname); 343214503Srpaulo goto failed; 344214503Srpaulo } 345214503Srpaulo 346214503Srpaulo if (pos == NULL) 347214503Srpaulo goto done; 348214503Srpaulo 349214503Srpaulo while (*pos == ' ' || *pos == '\t') 350214503Srpaulo pos++; 351214503Srpaulo if (*pos == '\0') 352214503Srpaulo goto done; 353214503Srpaulo 354214503Srpaulo if (os_strncmp(pos, "[ver=0]", 7) == 0) { 355214503Srpaulo user->force_version = 0; 356214503Srpaulo goto done; 357214503Srpaulo } 358214503Srpaulo 359214503Srpaulo if (os_strncmp(pos, "[ver=1]", 7) == 0) { 360214503Srpaulo user->force_version = 1; 361214503Srpaulo goto done; 362214503Srpaulo } 363214503Srpaulo 364214503Srpaulo if (os_strncmp(pos, "[2]", 3) == 0) { 365214503Srpaulo user->phase2 = 1; 366214503Srpaulo goto done; 367214503Srpaulo } 368214503Srpaulo 369214503Srpaulo if (*pos == '"') { 370214503Srpaulo pos++; 371214503Srpaulo start = pos; 372214503Srpaulo while (*pos != '"' && *pos != '\0') 373214503Srpaulo pos++; 374214503Srpaulo if (*pos == '\0') { 375214503Srpaulo wpa_printf(MSG_ERROR, "Invalid EAP password " 376214503Srpaulo "(no \" in end) on line %d in '%s'", 377214503Srpaulo line, fname); 378214503Srpaulo goto failed; 379214503Srpaulo } 380214503Srpaulo 381214503Srpaulo user->password = os_malloc(pos - start); 382214503Srpaulo if (user->password == NULL) { 383214503Srpaulo wpa_printf(MSG_ERROR, "Failed to allocate " 384214503Srpaulo "memory for EAP password"); 385214503Srpaulo goto failed; 386214503Srpaulo } 387214503Srpaulo os_memcpy(user->password, start, pos - start); 388214503Srpaulo user->password_len = pos - start; 389214503Srpaulo 390214503Srpaulo pos++; 391214503Srpaulo } else if (os_strncmp(pos, "hash:", 5) == 0) { 392214503Srpaulo pos += 5; 393214503Srpaulo pos2 = pos; 394214503Srpaulo while (*pos2 != '\0' && *pos2 != ' ' && 395214503Srpaulo *pos2 != '\t' && *pos2 != '#') 396214503Srpaulo pos2++; 397214503Srpaulo if (pos2 - pos != 32) { 398214503Srpaulo wpa_printf(MSG_ERROR, "Invalid password hash " 399214503Srpaulo "on line %d in '%s'", line, fname); 400214503Srpaulo goto failed; 401214503Srpaulo } 402214503Srpaulo user->password = os_malloc(16); 403214503Srpaulo if (user->password == NULL) { 404214503Srpaulo wpa_printf(MSG_ERROR, "Failed to allocate " 405214503Srpaulo "memory for EAP password hash"); 406214503Srpaulo goto failed; 407214503Srpaulo } 408214503Srpaulo if (hexstr2bin(pos, user->password, 16) < 0) { 409214503Srpaulo wpa_printf(MSG_ERROR, "Invalid hash password " 410214503Srpaulo "on line %d in '%s'", line, fname); 411214503Srpaulo goto failed; 412214503Srpaulo } 413214503Srpaulo user->password_len = 16; 414214503Srpaulo user->password_hash = 1; 415214503Srpaulo pos = pos2; 416214503Srpaulo } else { 417214503Srpaulo pos2 = pos; 418214503Srpaulo while (*pos2 != '\0' && *pos2 != ' ' && 419214503Srpaulo *pos2 != '\t' && *pos2 != '#') 420214503Srpaulo pos2++; 421214503Srpaulo if ((pos2 - pos) & 1) { 422214503Srpaulo wpa_printf(MSG_ERROR, "Invalid hex password " 423214503Srpaulo "on line %d in '%s'", line, fname); 424214503Srpaulo goto failed; 425214503Srpaulo } 426214503Srpaulo user->password = os_malloc((pos2 - pos) / 2); 427214503Srpaulo if (user->password == NULL) { 428214503Srpaulo wpa_printf(MSG_ERROR, "Failed to allocate " 429214503Srpaulo "memory for EAP password"); 430214503Srpaulo goto failed; 431214503Srpaulo } 432214503Srpaulo if (hexstr2bin(pos, user->password, 433214503Srpaulo (pos2 - pos) / 2) < 0) { 434214503Srpaulo wpa_printf(MSG_ERROR, "Invalid hex password " 435214503Srpaulo "on line %d in '%s'", line, fname); 436214503Srpaulo goto failed; 437214503Srpaulo } 438214503Srpaulo user->password_len = (pos2 - pos) / 2; 439214503Srpaulo pos = pos2; 440214503Srpaulo } 441214503Srpaulo 442214503Srpaulo while (*pos == ' ' || *pos == '\t') 443214503Srpaulo pos++; 444214503Srpaulo if (os_strncmp(pos, "[2]", 3) == 0) { 445214503Srpaulo user->phase2 = 1; 446214503Srpaulo } 447214503Srpaulo 448214503Srpaulo done: 449214503Srpaulo if (tail == NULL) { 450214503Srpaulo tail = conf->eap_user = user; 451214503Srpaulo } else { 452214503Srpaulo tail->next = user; 453214503Srpaulo tail = user; 454214503Srpaulo } 455214503Srpaulo continue; 456214503Srpaulo 457214503Srpaulo failed: 458214503Srpaulo if (user) { 459214503Srpaulo os_free(user->password); 460214503Srpaulo os_free(user->identity); 461214503Srpaulo os_free(user); 462214503Srpaulo } 463214503Srpaulo ret = -1; 464214503Srpaulo break; 465214503Srpaulo } 466214503Srpaulo 467214503Srpaulo fclose(f); 468214503Srpaulo 469214503Srpaulo return ret; 470214503Srpaulo} 471214503Srpaulo#endif /* EAP_SERVER */ 472214503Srpaulo 473214503Srpaulo 474214503Srpaulo#ifndef CONFIG_NO_RADIUS 475214503Srpaulostatic int 476214503Srpaulohostapd_config_read_radius_addr(struct hostapd_radius_server **server, 477214503Srpaulo int *num_server, const char *val, int def_port, 478214503Srpaulo struct hostapd_radius_server **curr_serv) 479214503Srpaulo{ 480214503Srpaulo struct hostapd_radius_server *nserv; 481214503Srpaulo int ret; 482214503Srpaulo static int server_index = 1; 483214503Srpaulo 484252726Srpaulo nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv)); 485214503Srpaulo if (nserv == NULL) 486214503Srpaulo return -1; 487214503Srpaulo 488214503Srpaulo *server = nserv; 489214503Srpaulo nserv = &nserv[*num_server]; 490214503Srpaulo (*num_server)++; 491214503Srpaulo (*curr_serv) = nserv; 492214503Srpaulo 493214503Srpaulo os_memset(nserv, 0, sizeof(*nserv)); 494214503Srpaulo nserv->port = def_port; 495214503Srpaulo ret = hostapd_parse_ip_addr(val, &nserv->addr); 496214503Srpaulo nserv->index = server_index++; 497214503Srpaulo 498214503Srpaulo return ret; 499214503Srpaulo} 500252726Srpaulo 501252726Srpaulo 502252726Srpaulostatic struct hostapd_radius_attr * 503252726Srpaulohostapd_parse_radius_attr(const char *value) 504252726Srpaulo{ 505252726Srpaulo const char *pos; 506252726Srpaulo char syntax; 507252726Srpaulo struct hostapd_radius_attr *attr; 508252726Srpaulo size_t len; 509252726Srpaulo 510252726Srpaulo attr = os_zalloc(sizeof(*attr)); 511252726Srpaulo if (attr == NULL) 512252726Srpaulo return NULL; 513252726Srpaulo 514252726Srpaulo attr->type = atoi(value); 515252726Srpaulo 516252726Srpaulo pos = os_strchr(value, ':'); 517252726Srpaulo if (pos == NULL) { 518252726Srpaulo attr->val = wpabuf_alloc(1); 519252726Srpaulo if (attr->val == NULL) { 520252726Srpaulo os_free(attr); 521252726Srpaulo return NULL; 522252726Srpaulo } 523252726Srpaulo wpabuf_put_u8(attr->val, 0); 524252726Srpaulo return attr; 525252726Srpaulo } 526252726Srpaulo 527252726Srpaulo pos++; 528252726Srpaulo if (pos[0] == '\0' || pos[1] != ':') { 529252726Srpaulo os_free(attr); 530252726Srpaulo return NULL; 531252726Srpaulo } 532252726Srpaulo syntax = *pos++; 533252726Srpaulo pos++; 534252726Srpaulo 535252726Srpaulo switch (syntax) { 536252726Srpaulo case 's': 537252726Srpaulo attr->val = wpabuf_alloc_copy(pos, os_strlen(pos)); 538252726Srpaulo break; 539252726Srpaulo case 'x': 540252726Srpaulo len = os_strlen(pos); 541252726Srpaulo if (len & 1) 542252726Srpaulo break; 543252726Srpaulo len /= 2; 544252726Srpaulo attr->val = wpabuf_alloc(len); 545252726Srpaulo if (attr->val == NULL) 546252726Srpaulo break; 547252726Srpaulo if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) { 548252726Srpaulo wpabuf_free(attr->val); 549252726Srpaulo os_free(attr); 550252726Srpaulo return NULL; 551252726Srpaulo } 552252726Srpaulo break; 553252726Srpaulo case 'd': 554252726Srpaulo attr->val = wpabuf_alloc(4); 555252726Srpaulo if (attr->val) 556252726Srpaulo wpabuf_put_be32(attr->val, atoi(pos)); 557252726Srpaulo break; 558252726Srpaulo default: 559252726Srpaulo os_free(attr); 560252726Srpaulo return NULL; 561252726Srpaulo } 562252726Srpaulo 563252726Srpaulo if (attr->val == NULL) { 564252726Srpaulo os_free(attr); 565252726Srpaulo return NULL; 566252726Srpaulo } 567252726Srpaulo 568252726Srpaulo return attr; 569252726Srpaulo} 570252726Srpaulo 571252726Srpaulo 572252726Srpaulostatic int hostapd_parse_das_client(struct hostapd_bss_config *bss, 573252726Srpaulo const char *val) 574252726Srpaulo{ 575252726Srpaulo char *secret; 576252726Srpaulo 577252726Srpaulo secret = os_strchr(val, ' '); 578252726Srpaulo if (secret == NULL) 579252726Srpaulo return -1; 580252726Srpaulo 581252726Srpaulo secret++; 582252726Srpaulo 583252726Srpaulo if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr)) 584252726Srpaulo return -1; 585252726Srpaulo 586252726Srpaulo os_free(bss->radius_das_shared_secret); 587252726Srpaulo bss->radius_das_shared_secret = (u8 *) os_strdup(secret); 588252726Srpaulo if (bss->radius_das_shared_secret == NULL) 589252726Srpaulo return -1; 590252726Srpaulo bss->radius_das_shared_secret_len = os_strlen(secret); 591252726Srpaulo 592252726Srpaulo return 0; 593252726Srpaulo} 594214503Srpaulo#endif /* CONFIG_NO_RADIUS */ 595214503Srpaulo 596214503Srpaulo 597214503Srpaulostatic int hostapd_config_parse_key_mgmt(int line, const char *value) 598214503Srpaulo{ 599214503Srpaulo int val = 0, last; 600214503Srpaulo char *start, *end, *buf; 601214503Srpaulo 602214503Srpaulo buf = os_strdup(value); 603214503Srpaulo if (buf == NULL) 604214503Srpaulo return -1; 605214503Srpaulo start = buf; 606214503Srpaulo 607214503Srpaulo while (*start != '\0') { 608214503Srpaulo while (*start == ' ' || *start == '\t') 609214503Srpaulo start++; 610214503Srpaulo if (*start == '\0') 611214503Srpaulo break; 612214503Srpaulo end = start; 613214503Srpaulo while (*end != ' ' && *end != '\t' && *end != '\0') 614214503Srpaulo end++; 615214503Srpaulo last = *end == '\0'; 616214503Srpaulo *end = '\0'; 617214503Srpaulo if (os_strcmp(start, "WPA-PSK") == 0) 618214503Srpaulo val |= WPA_KEY_MGMT_PSK; 619214503Srpaulo else if (os_strcmp(start, "WPA-EAP") == 0) 620214503Srpaulo val |= WPA_KEY_MGMT_IEEE8021X; 621214503Srpaulo#ifdef CONFIG_IEEE80211R 622214503Srpaulo else if (os_strcmp(start, "FT-PSK") == 0) 623214503Srpaulo val |= WPA_KEY_MGMT_FT_PSK; 624214503Srpaulo else if (os_strcmp(start, "FT-EAP") == 0) 625214503Srpaulo val |= WPA_KEY_MGMT_FT_IEEE8021X; 626214503Srpaulo#endif /* CONFIG_IEEE80211R */ 627214503Srpaulo#ifdef CONFIG_IEEE80211W 628214503Srpaulo else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) 629214503Srpaulo val |= WPA_KEY_MGMT_PSK_SHA256; 630214503Srpaulo else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) 631214503Srpaulo val |= WPA_KEY_MGMT_IEEE8021X_SHA256; 632214503Srpaulo#endif /* CONFIG_IEEE80211W */ 633252726Srpaulo#ifdef CONFIG_SAE 634252726Srpaulo else if (os_strcmp(start, "SAE") == 0) 635252726Srpaulo val |= WPA_KEY_MGMT_SAE; 636252726Srpaulo else if (os_strcmp(start, "FT-SAE") == 0) 637252726Srpaulo val |= WPA_KEY_MGMT_FT_SAE; 638252726Srpaulo#endif /* CONFIG_SAE */ 639214503Srpaulo else { 640214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", 641214503Srpaulo line, start); 642214503Srpaulo os_free(buf); 643214503Srpaulo return -1; 644214503Srpaulo } 645214503Srpaulo 646214503Srpaulo if (last) 647214503Srpaulo break; 648214503Srpaulo start = end + 1; 649214503Srpaulo } 650214503Srpaulo 651214503Srpaulo os_free(buf); 652214503Srpaulo if (val == 0) { 653214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values " 654214503Srpaulo "configured.", line); 655214503Srpaulo return -1; 656214503Srpaulo } 657214503Srpaulo 658214503Srpaulo return val; 659214503Srpaulo} 660214503Srpaulo 661214503Srpaulo 662214503Srpaulostatic int hostapd_config_parse_cipher(int line, const char *value) 663214503Srpaulo{ 664214503Srpaulo int val = 0, last; 665214503Srpaulo char *start, *end, *buf; 666214503Srpaulo 667214503Srpaulo buf = os_strdup(value); 668214503Srpaulo if (buf == NULL) 669214503Srpaulo return -1; 670214503Srpaulo start = buf; 671214503Srpaulo 672214503Srpaulo while (*start != '\0') { 673214503Srpaulo while (*start == ' ' || *start == '\t') 674214503Srpaulo start++; 675214503Srpaulo if (*start == '\0') 676214503Srpaulo break; 677214503Srpaulo end = start; 678214503Srpaulo while (*end != ' ' && *end != '\t' && *end != '\0') 679214503Srpaulo end++; 680214503Srpaulo last = *end == '\0'; 681214503Srpaulo *end = '\0'; 682214503Srpaulo if (os_strcmp(start, "CCMP") == 0) 683214503Srpaulo val |= WPA_CIPHER_CCMP; 684252726Srpaulo else if (os_strcmp(start, "GCMP") == 0) 685252726Srpaulo val |= WPA_CIPHER_GCMP; 686214503Srpaulo else if (os_strcmp(start, "TKIP") == 0) 687214503Srpaulo val |= WPA_CIPHER_TKIP; 688214503Srpaulo else if (os_strcmp(start, "WEP104") == 0) 689214503Srpaulo val |= WPA_CIPHER_WEP104; 690214503Srpaulo else if (os_strcmp(start, "WEP40") == 0) 691214503Srpaulo val |= WPA_CIPHER_WEP40; 692214503Srpaulo else if (os_strcmp(start, "NONE") == 0) 693214503Srpaulo val |= WPA_CIPHER_NONE; 694214503Srpaulo else { 695214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", 696214503Srpaulo line, start); 697214503Srpaulo os_free(buf); 698214503Srpaulo return -1; 699214503Srpaulo } 700214503Srpaulo 701214503Srpaulo if (last) 702214503Srpaulo break; 703214503Srpaulo start = end + 1; 704214503Srpaulo } 705214503Srpaulo os_free(buf); 706214503Srpaulo 707214503Srpaulo if (val == 0) { 708214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", 709214503Srpaulo line); 710214503Srpaulo return -1; 711214503Srpaulo } 712214503Srpaulo return val; 713214503Srpaulo} 714214503Srpaulo 715214503Srpaulo 716214503Srpaulostatic int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx, 717214503Srpaulo char *val) 718214503Srpaulo{ 719214503Srpaulo size_t len = os_strlen(val); 720214503Srpaulo 721214503Srpaulo if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL) 722214503Srpaulo return -1; 723214503Srpaulo 724214503Srpaulo if (val[0] == '"') { 725214503Srpaulo if (len < 2 || val[len - 1] != '"') 726214503Srpaulo return -1; 727214503Srpaulo len -= 2; 728214503Srpaulo wep->key[keyidx] = os_malloc(len); 729214503Srpaulo if (wep->key[keyidx] == NULL) 730214503Srpaulo return -1; 731214503Srpaulo os_memcpy(wep->key[keyidx], val + 1, len); 732214503Srpaulo wep->len[keyidx] = len; 733214503Srpaulo } else { 734214503Srpaulo if (len & 1) 735214503Srpaulo return -1; 736214503Srpaulo len /= 2; 737214503Srpaulo wep->key[keyidx] = os_malloc(len); 738214503Srpaulo if (wep->key[keyidx] == NULL) 739214503Srpaulo return -1; 740214503Srpaulo wep->len[keyidx] = len; 741214503Srpaulo if (hexstr2bin(val, wep->key[keyidx], len) < 0) 742214503Srpaulo return -1; 743214503Srpaulo } 744214503Srpaulo 745214503Srpaulo wep->keys_set++; 746214503Srpaulo 747214503Srpaulo return 0; 748214503Srpaulo} 749214503Srpaulo 750214503Srpaulo 751214503Srpaulostatic int hostapd_parse_rates(int **rate_list, char *val) 752214503Srpaulo{ 753214503Srpaulo int *list; 754214503Srpaulo int count; 755214503Srpaulo char *pos, *end; 756214503Srpaulo 757214503Srpaulo os_free(*rate_list); 758214503Srpaulo *rate_list = NULL; 759214503Srpaulo 760214503Srpaulo pos = val; 761214503Srpaulo count = 0; 762214503Srpaulo while (*pos != '\0') { 763214503Srpaulo if (*pos == ' ') 764214503Srpaulo count++; 765214503Srpaulo pos++; 766214503Srpaulo } 767214503Srpaulo 768214503Srpaulo list = os_malloc(sizeof(int) * (count + 2)); 769214503Srpaulo if (list == NULL) 770214503Srpaulo return -1; 771214503Srpaulo pos = val; 772214503Srpaulo count = 0; 773214503Srpaulo while (*pos != '\0') { 774214503Srpaulo end = os_strchr(pos, ' '); 775214503Srpaulo if (end) 776214503Srpaulo *end = '\0'; 777214503Srpaulo 778214503Srpaulo list[count++] = atoi(pos); 779214503Srpaulo if (!end) 780214503Srpaulo break; 781214503Srpaulo pos = end + 1; 782214503Srpaulo } 783214503Srpaulo list[count] = -1; 784214503Srpaulo 785214503Srpaulo *rate_list = list; 786214503Srpaulo return 0; 787214503Srpaulo} 788214503Srpaulo 789214503Srpaulo 790214503Srpaulostatic int hostapd_config_bss(struct hostapd_config *conf, const char *ifname) 791214503Srpaulo{ 792214503Srpaulo struct hostapd_bss_config *bss; 793214503Srpaulo 794214503Srpaulo if (*ifname == '\0') 795214503Srpaulo return -1; 796214503Srpaulo 797252726Srpaulo bss = os_realloc_array(conf->bss, conf->num_bss + 1, 798252726Srpaulo sizeof(struct hostapd_bss_config)); 799214503Srpaulo if (bss == NULL) { 800214503Srpaulo wpa_printf(MSG_ERROR, "Failed to allocate memory for " 801214503Srpaulo "multi-BSS entry"); 802214503Srpaulo return -1; 803214503Srpaulo } 804214503Srpaulo conf->bss = bss; 805214503Srpaulo 806214503Srpaulo bss = &(conf->bss[conf->num_bss]); 807214503Srpaulo os_memset(bss, 0, sizeof(*bss)); 808214503Srpaulo bss->radius = os_zalloc(sizeof(*bss->radius)); 809214503Srpaulo if (bss->radius == NULL) { 810214503Srpaulo wpa_printf(MSG_ERROR, "Failed to allocate memory for " 811214503Srpaulo "multi-BSS RADIUS data"); 812214503Srpaulo return -1; 813214503Srpaulo } 814214503Srpaulo 815214503Srpaulo conf->num_bss++; 816214503Srpaulo conf->last_bss = bss; 817214503Srpaulo 818214503Srpaulo hostapd_config_defaults_bss(bss); 819214503Srpaulo os_strlcpy(bss->iface, ifname, sizeof(bss->iface)); 820214503Srpaulo os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1); 821214503Srpaulo 822214503Srpaulo return 0; 823214503Srpaulo} 824214503Srpaulo 825214503Srpaulo 826214503Srpaulo/* convert floats with one decimal place to value*10 int, i.e., 827214503Srpaulo * "1.5" will return 15 */ 828214503Srpaulostatic int hostapd_config_read_int10(const char *value) 829214503Srpaulo{ 830214503Srpaulo int i, d; 831214503Srpaulo char *pos; 832214503Srpaulo 833214503Srpaulo i = atoi(value); 834214503Srpaulo pos = os_strchr(value, '.'); 835214503Srpaulo d = 0; 836214503Srpaulo if (pos) { 837214503Srpaulo pos++; 838214503Srpaulo if (*pos >= '0' && *pos <= '9') 839214503Srpaulo d = *pos - '0'; 840214503Srpaulo } 841214503Srpaulo 842214503Srpaulo return i * 10 + d; 843214503Srpaulo} 844214503Srpaulo 845214503Srpaulo 846214503Srpaulostatic int valid_cw(int cw) 847214503Srpaulo{ 848214503Srpaulo return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 || 849214503Srpaulo cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023); 850214503Srpaulo} 851214503Srpaulo 852214503Srpaulo 853214503Srpauloenum { 854214503Srpaulo IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */ 855214503Srpaulo IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */ 856214503Srpaulo IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */ 857252726Srpaulo IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */ 858214503Srpaulo}; 859214503Srpaulo 860214503Srpaulostatic int hostapd_config_tx_queue(struct hostapd_config *conf, char *name, 861214503Srpaulo char *val) 862214503Srpaulo{ 863214503Srpaulo int num; 864214503Srpaulo char *pos; 865214503Srpaulo struct hostapd_tx_queue_params *queue; 866214503Srpaulo 867214503Srpaulo /* skip 'tx_queue_' prefix */ 868214503Srpaulo pos = name + 9; 869214503Srpaulo if (os_strncmp(pos, "data", 4) == 0 && 870214503Srpaulo pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') { 871214503Srpaulo num = pos[4] - '0'; 872214503Srpaulo pos += 6; 873252726Srpaulo } else if (os_strncmp(pos, "after_beacon_", 13) == 0 || 874252726Srpaulo os_strncmp(pos, "beacon_", 7) == 0) { 875252726Srpaulo wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); 876252726Srpaulo return 0; 877214503Srpaulo } else { 878214503Srpaulo wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos); 879214503Srpaulo return -1; 880214503Srpaulo } 881214503Srpaulo 882252726Srpaulo if (num >= NUM_TX_QUEUES) { 883252726Srpaulo /* for backwards compatibility, do not trigger failure */ 884252726Srpaulo wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); 885252726Srpaulo return 0; 886252726Srpaulo } 887252726Srpaulo 888214503Srpaulo queue = &conf->tx_queue[num]; 889214503Srpaulo 890214503Srpaulo if (os_strcmp(pos, "aifs") == 0) { 891214503Srpaulo queue->aifs = atoi(val); 892214503Srpaulo if (queue->aifs < 0 || queue->aifs > 255) { 893214503Srpaulo wpa_printf(MSG_ERROR, "Invalid AIFS value %d", 894214503Srpaulo queue->aifs); 895214503Srpaulo return -1; 896214503Srpaulo } 897214503Srpaulo } else if (os_strcmp(pos, "cwmin") == 0) { 898214503Srpaulo queue->cwmin = atoi(val); 899214503Srpaulo if (!valid_cw(queue->cwmin)) { 900214503Srpaulo wpa_printf(MSG_ERROR, "Invalid cwMin value %d", 901214503Srpaulo queue->cwmin); 902214503Srpaulo return -1; 903214503Srpaulo } 904214503Srpaulo } else if (os_strcmp(pos, "cwmax") == 0) { 905214503Srpaulo queue->cwmax = atoi(val); 906214503Srpaulo if (!valid_cw(queue->cwmax)) { 907214503Srpaulo wpa_printf(MSG_ERROR, "Invalid cwMax value %d", 908214503Srpaulo queue->cwmax); 909214503Srpaulo return -1; 910214503Srpaulo } 911214503Srpaulo } else if (os_strcmp(pos, "burst") == 0) { 912214503Srpaulo queue->burst = hostapd_config_read_int10(val); 913214503Srpaulo } else { 914214503Srpaulo wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos); 915214503Srpaulo return -1; 916214503Srpaulo } 917214503Srpaulo 918214503Srpaulo return 0; 919214503Srpaulo} 920214503Srpaulo 921214503Srpaulo 922214503Srpaulo#ifdef CONFIG_IEEE80211R 923214503Srpaulostatic int add_r0kh(struct hostapd_bss_config *bss, char *value) 924214503Srpaulo{ 925214503Srpaulo struct ft_remote_r0kh *r0kh; 926214503Srpaulo char *pos, *next; 927214503Srpaulo 928214503Srpaulo r0kh = os_zalloc(sizeof(*r0kh)); 929214503Srpaulo if (r0kh == NULL) 930214503Srpaulo return -1; 931214503Srpaulo 932214503Srpaulo /* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */ 933214503Srpaulo pos = value; 934214503Srpaulo next = os_strchr(pos, ' '); 935214503Srpaulo if (next) 936214503Srpaulo *next++ = '\0'; 937214503Srpaulo if (next == NULL || hwaddr_aton(pos, r0kh->addr)) { 938214503Srpaulo wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos); 939214503Srpaulo os_free(r0kh); 940214503Srpaulo return -1; 941214503Srpaulo } 942214503Srpaulo 943214503Srpaulo pos = next; 944214503Srpaulo next = os_strchr(pos, ' '); 945214503Srpaulo if (next) 946214503Srpaulo *next++ = '\0'; 947214503Srpaulo if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) { 948214503Srpaulo wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos); 949214503Srpaulo os_free(r0kh); 950214503Srpaulo return -1; 951214503Srpaulo } 952214503Srpaulo r0kh->id_len = next - pos - 1; 953214503Srpaulo os_memcpy(r0kh->id, pos, r0kh->id_len); 954214503Srpaulo 955214503Srpaulo pos = next; 956214503Srpaulo if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) { 957214503Srpaulo wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos); 958214503Srpaulo os_free(r0kh); 959214503Srpaulo return -1; 960214503Srpaulo } 961214503Srpaulo 962214503Srpaulo r0kh->next = bss->r0kh_list; 963214503Srpaulo bss->r0kh_list = r0kh; 964214503Srpaulo 965214503Srpaulo return 0; 966214503Srpaulo} 967214503Srpaulo 968214503Srpaulo 969214503Srpaulostatic int add_r1kh(struct hostapd_bss_config *bss, char *value) 970214503Srpaulo{ 971214503Srpaulo struct ft_remote_r1kh *r1kh; 972214503Srpaulo char *pos, *next; 973214503Srpaulo 974214503Srpaulo r1kh = os_zalloc(sizeof(*r1kh)); 975214503Srpaulo if (r1kh == NULL) 976214503Srpaulo return -1; 977214503Srpaulo 978214503Srpaulo /* 02:01:02:03:04:05 02:01:02:03:04:05 979214503Srpaulo * 000102030405060708090a0b0c0d0e0f */ 980214503Srpaulo pos = value; 981214503Srpaulo next = os_strchr(pos, ' '); 982214503Srpaulo if (next) 983214503Srpaulo *next++ = '\0'; 984214503Srpaulo if (next == NULL || hwaddr_aton(pos, r1kh->addr)) { 985214503Srpaulo wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos); 986214503Srpaulo os_free(r1kh); 987214503Srpaulo return -1; 988214503Srpaulo } 989214503Srpaulo 990214503Srpaulo pos = next; 991214503Srpaulo next = os_strchr(pos, ' '); 992214503Srpaulo if (next) 993214503Srpaulo *next++ = '\0'; 994214503Srpaulo if (next == NULL || hwaddr_aton(pos, r1kh->id)) { 995214503Srpaulo wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos); 996214503Srpaulo os_free(r1kh); 997214503Srpaulo return -1; 998214503Srpaulo } 999214503Srpaulo 1000214503Srpaulo pos = next; 1001214503Srpaulo if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) { 1002214503Srpaulo wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos); 1003214503Srpaulo os_free(r1kh); 1004214503Srpaulo return -1; 1005214503Srpaulo } 1006214503Srpaulo 1007214503Srpaulo r1kh->next = bss->r1kh_list; 1008214503Srpaulo bss->r1kh_list = r1kh; 1009214503Srpaulo 1010214503Srpaulo return 0; 1011214503Srpaulo} 1012214503Srpaulo#endif /* CONFIG_IEEE80211R */ 1013214503Srpaulo 1014214503Srpaulo 1015214503Srpaulo#ifdef CONFIG_IEEE80211N 1016214503Srpaulostatic int hostapd_config_ht_capab(struct hostapd_config *conf, 1017214503Srpaulo const char *capab) 1018214503Srpaulo{ 1019214503Srpaulo if (os_strstr(capab, "[LDPC]")) 1020214503Srpaulo conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP; 1021214503Srpaulo if (os_strstr(capab, "[HT40-]")) { 1022214503Srpaulo conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; 1023214503Srpaulo conf->secondary_channel = -1; 1024214503Srpaulo } 1025214503Srpaulo if (os_strstr(capab, "[HT40+]")) { 1026214503Srpaulo conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; 1027214503Srpaulo conf->secondary_channel = 1; 1028214503Srpaulo } 1029214503Srpaulo if (os_strstr(capab, "[SMPS-STATIC]")) { 1030214503Srpaulo conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK; 1031214503Srpaulo conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC; 1032214503Srpaulo } 1033214503Srpaulo if (os_strstr(capab, "[SMPS-DYNAMIC]")) { 1034214503Srpaulo conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK; 1035214503Srpaulo conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC; 1036214503Srpaulo } 1037214503Srpaulo if (os_strstr(capab, "[GF]")) 1038214503Srpaulo conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD; 1039214503Srpaulo if (os_strstr(capab, "[SHORT-GI-20]")) 1040214503Srpaulo conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ; 1041214503Srpaulo if (os_strstr(capab, "[SHORT-GI-40]")) 1042214503Srpaulo conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ; 1043214503Srpaulo if (os_strstr(capab, "[TX-STBC]")) 1044214503Srpaulo conf->ht_capab |= HT_CAP_INFO_TX_STBC; 1045214503Srpaulo if (os_strstr(capab, "[RX-STBC1]")) { 1046214503Srpaulo conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK; 1047214503Srpaulo conf->ht_capab |= HT_CAP_INFO_RX_STBC_1; 1048214503Srpaulo } 1049214503Srpaulo if (os_strstr(capab, "[RX-STBC12]")) { 1050214503Srpaulo conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK; 1051214503Srpaulo conf->ht_capab |= HT_CAP_INFO_RX_STBC_12; 1052214503Srpaulo } 1053214503Srpaulo if (os_strstr(capab, "[RX-STBC123]")) { 1054214503Srpaulo conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK; 1055214503Srpaulo conf->ht_capab |= HT_CAP_INFO_RX_STBC_123; 1056214503Srpaulo } 1057214503Srpaulo if (os_strstr(capab, "[DELAYED-BA]")) 1058214503Srpaulo conf->ht_capab |= HT_CAP_INFO_DELAYED_BA; 1059214503Srpaulo if (os_strstr(capab, "[MAX-AMSDU-7935]")) 1060214503Srpaulo conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE; 1061214503Srpaulo if (os_strstr(capab, "[DSSS_CCK-40]")) 1062214503Srpaulo conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ; 1063214503Srpaulo if (os_strstr(capab, "[PSMP]")) 1064214503Srpaulo conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP; 1065214503Srpaulo if (os_strstr(capab, "[LSIG-TXOP-PROT]")) 1066214503Srpaulo conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT; 1067214503Srpaulo 1068214503Srpaulo return 0; 1069214503Srpaulo} 1070214503Srpaulo#endif /* CONFIG_IEEE80211N */ 1071214503Srpaulo 1072214503Srpaulo 1073252726Srpaulo#ifdef CONFIG_IEEE80211AC 1074252726Srpaulostatic int hostapd_config_vht_capab(struct hostapd_config *conf, 1075252726Srpaulo const char *capab) 1076252726Srpaulo{ 1077252726Srpaulo if (os_strstr(capab, "[MAX-MPDU-7991]")) 1078252726Srpaulo conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991; 1079252726Srpaulo if (os_strstr(capab, "[MAX-MPDU-11454]")) 1080252726Srpaulo conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454; 1081252726Srpaulo if (os_strstr(capab, "[VHT160]")) 1082252726Srpaulo conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; 1083252726Srpaulo if (os_strstr(capab, "[VHT160-80PLUS80]")) 1084252726Srpaulo conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; 1085252726Srpaulo if (os_strstr(capab, "[VHT160-80PLUS80]")) 1086252726Srpaulo conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; 1087252726Srpaulo if (os_strstr(capab, "[RXLDPC]")) 1088252726Srpaulo conf->vht_capab |= VHT_CAP_RXLDPC; 1089252726Srpaulo if (os_strstr(capab, "[SHORT-GI-80]")) 1090252726Srpaulo conf->vht_capab |= VHT_CAP_SHORT_GI_80; 1091252726Srpaulo if (os_strstr(capab, "[SHORT-GI-160]")) 1092252726Srpaulo conf->vht_capab |= VHT_CAP_SHORT_GI_160; 1093252726Srpaulo if (os_strstr(capab, "[TX-STBC-2BY1]")) 1094252726Srpaulo conf->vht_capab |= VHT_CAP_TXSTBC; 1095252726Srpaulo if (os_strstr(capab, "[RX-STBC-1]")) 1096252726Srpaulo conf->vht_capab |= VHT_CAP_RXSTBC_1; 1097252726Srpaulo if (os_strstr(capab, "[RX-STBC-12]")) 1098252726Srpaulo conf->vht_capab |= VHT_CAP_RXSTBC_2; 1099252726Srpaulo if (os_strstr(capab, "[RX-STBC-123]")) 1100252726Srpaulo conf->vht_capab |= VHT_CAP_RXSTBC_3; 1101252726Srpaulo if (os_strstr(capab, "[RX-STBC-1234]")) 1102252726Srpaulo conf->vht_capab |= VHT_CAP_RXSTBC_4; 1103252726Srpaulo if (os_strstr(capab, "[SU-BEAMFORMER]")) 1104252726Srpaulo conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE; 1105252726Srpaulo if (os_strstr(capab, "[SU-BEAMFORMEE]")) 1106252726Srpaulo conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE; 1107252726Srpaulo if (os_strstr(capab, "[BF-ANTENNA-2]") && 1108252726Srpaulo (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE)) 1109252726Srpaulo conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX; 1110252726Srpaulo if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") && 1111252726Srpaulo (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE)) 1112252726Srpaulo conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX; 1113252726Srpaulo if (os_strstr(capab, "[MU-BEAMFORMER]")) 1114252726Srpaulo conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE; 1115252726Srpaulo if (os_strstr(capab, "[MU-BEAMFORMEE]")) 1116252726Srpaulo conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE; 1117252726Srpaulo if (os_strstr(capab, "[VHT-TXOP-PS]")) 1118252726Srpaulo conf->vht_capab |= VHT_CAP_VHT_TXOP_PS; 1119252726Srpaulo if (os_strstr(capab, "[HTC-VHT]")) 1120252726Srpaulo conf->vht_capab |= VHT_CAP_HTC_VHT; 1121252726Srpaulo if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]")) 1122252726Srpaulo conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT; 1123252726Srpaulo if (os_strstr(capab, "[VHT-LINK-ADAPT2]") && 1124252726Srpaulo (conf->vht_capab & VHT_CAP_HTC_VHT)) 1125252726Srpaulo conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB; 1126252726Srpaulo if (os_strstr(capab, "[VHT-LINK-ADAPT3]") && 1127252726Srpaulo (conf->vht_capab & VHT_CAP_HTC_VHT)) 1128252726Srpaulo conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; 1129252726Srpaulo if (os_strstr(capab, "[RX-ANTENNA-PATTERN]")) 1130252726Srpaulo conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN; 1131252726Srpaulo if (os_strstr(capab, "[TX-ANTENNA-PATTERN]")) 1132252726Srpaulo conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN; 1133252726Srpaulo return 0; 1134252726Srpaulo} 1135252726Srpaulo#endif /* CONFIG_IEEE80211AC */ 1136252726Srpaulo 1137252726Srpaulo 1138214503Srpaulostatic int hostapd_config_check_bss(struct hostapd_bss_config *bss, 1139214503Srpaulo struct hostapd_config *conf) 1140214503Srpaulo{ 1141214503Srpaulo if (bss->ieee802_1x && !bss->eap_server && 1142214503Srpaulo !bss->radius->auth_servers) { 1143214503Srpaulo wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no " 1144214503Srpaulo "EAP authenticator configured)."); 1145214503Srpaulo return -1; 1146214503Srpaulo } 1147214503Srpaulo 1148252726Srpaulo if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED && 1149252726Srpaulo bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { 1150252726Srpaulo wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no " 1151252726Srpaulo "RADIUS checking (macaddr_acl=2) enabled."); 1152252726Srpaulo return -1; 1153252726Srpaulo } 1154252726Srpaulo 1155214503Srpaulo if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) && 1156214503Srpaulo bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL && 1157252726Srpaulo bss->ssid.wpa_psk_file == NULL && 1158252726Srpaulo (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED || 1159252726Srpaulo bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) { 1160214503Srpaulo wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase " 1161214503Srpaulo "is not configured."); 1162214503Srpaulo return -1; 1163214503Srpaulo } 1164214503Srpaulo 1165214503Srpaulo if (hostapd_mac_comp_empty(bss->bssid) != 0) { 1166214503Srpaulo size_t i; 1167214503Srpaulo 1168214503Srpaulo for (i = 0; i < conf->num_bss; i++) { 1169214503Srpaulo if ((&conf->bss[i] != bss) && 1170214503Srpaulo (hostapd_mac_comp(conf->bss[i].bssid, 1171214503Srpaulo bss->bssid) == 0)) { 1172214503Srpaulo wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR 1173214503Srpaulo " on interface '%s' and '%s'.", 1174214503Srpaulo MAC2STR(bss->bssid), 1175214503Srpaulo conf->bss[i].iface, bss->iface); 1176214503Srpaulo return -1; 1177214503Srpaulo } 1178214503Srpaulo } 1179214503Srpaulo } 1180214503Srpaulo 1181214503Srpaulo#ifdef CONFIG_IEEE80211R 1182252726Srpaulo if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) && 1183214503Srpaulo (bss->nas_identifier == NULL || 1184214503Srpaulo os_strlen(bss->nas_identifier) < 1 || 1185214503Srpaulo os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) { 1186214503Srpaulo wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires " 1187214503Srpaulo "nas_identifier to be configured as a 1..48 octet " 1188214503Srpaulo "string"); 1189214503Srpaulo return -1; 1190214503Srpaulo } 1191214503Srpaulo#endif /* CONFIG_IEEE80211R */ 1192214503Srpaulo 1193214503Srpaulo#ifdef CONFIG_IEEE80211N 1194252726Srpaulo if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) { 1195252726Srpaulo bss->disable_11n = 1; 1196252726Srpaulo wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not " 1197252726Srpaulo "allowed, disabling HT capabilites"); 1198252726Srpaulo } 1199252726Srpaulo 1200252726Srpaulo if (conf->ieee80211n && 1201252726Srpaulo bss->ssid.security_policy == SECURITY_STATIC_WEP) { 1202252726Srpaulo bss->disable_11n = 1; 1203252726Srpaulo wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not " 1204252726Srpaulo "allowed, disabling HT capabilities"); 1205252726Srpaulo } 1206252726Srpaulo 1207214503Srpaulo if (conf->ieee80211n && bss->wpa && 1208214503Srpaulo !(bss->wpa_pairwise & WPA_CIPHER_CCMP) && 1209252726Srpaulo !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) { 1210252726Srpaulo bss->disable_11n = 1; 1211214503Srpaulo wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 " 1212252726Srpaulo "requires CCMP/GCMP to be enabled, disabling HT " 1213252726Srpaulo "capabilities"); 1214214503Srpaulo } 1215214503Srpaulo#endif /* CONFIG_IEEE80211N */ 1216214503Srpaulo 1217252726Srpaulo#ifdef CONFIG_WPS2 1218252726Srpaulo if (bss->wps_state && bss->ignore_broadcast_ssid) { 1219252726Srpaulo wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid " 1220252726Srpaulo "configuration forced WPS to be disabled"); 1221252726Srpaulo bss->wps_state = 0; 1222252726Srpaulo } 1223252726Srpaulo 1224252726Srpaulo if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) { 1225252726Srpaulo wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be " 1226252726Srpaulo "disabled"); 1227252726Srpaulo bss->wps_state = 0; 1228252726Srpaulo } 1229252726Srpaulo 1230252726Srpaulo if (bss->wps_state && bss->wpa && 1231252726Srpaulo (!(bss->wpa & 2) || 1232252726Srpaulo !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) { 1233252726Srpaulo wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without " 1234252726Srpaulo "WPA2/CCMP forced WPS to be disabled"); 1235252726Srpaulo bss->wps_state = 0; 1236252726Srpaulo } 1237252726Srpaulo#endif /* CONFIG_WPS2 */ 1238252726Srpaulo 1239252726Srpaulo#ifdef CONFIG_HS20 1240252726Srpaulo if (bss->hs20 && 1241252726Srpaulo (!(bss->wpa & 2) || 1242252726Srpaulo !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) { 1243252726Srpaulo wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP " 1244252726Srpaulo "configuration is required for Hotspot 2.0 " 1245252726Srpaulo "functionality"); 1246252726Srpaulo return -1; 1247252726Srpaulo } 1248252726Srpaulo#endif /* CONFIG_HS20 */ 1249252726Srpaulo 1250214503Srpaulo return 0; 1251214503Srpaulo} 1252214503Srpaulo 1253214503Srpaulo 1254214503Srpaulostatic int hostapd_config_check(struct hostapd_config *conf) 1255214503Srpaulo{ 1256214503Srpaulo size_t i; 1257214503Srpaulo 1258214503Srpaulo if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) { 1259214503Srpaulo wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without " 1260214503Srpaulo "setting the country_code"); 1261214503Srpaulo return -1; 1262214503Srpaulo } 1263214503Srpaulo 1264214503Srpaulo for (i = 0; i < conf->num_bss; i++) { 1265214503Srpaulo if (hostapd_config_check_bss(&conf->bss[i], conf)) 1266214503Srpaulo return -1; 1267214503Srpaulo } 1268214503Srpaulo 1269214503Srpaulo return 0; 1270214503Srpaulo} 1271214503Srpaulo 1272214503Srpaulo 1273252726Srpaulo#ifdef CONFIG_INTERWORKING 1274252726Srpaulostatic int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos, 1275252726Srpaulo int line) 1276214503Srpaulo{ 1277252726Srpaulo size_t len = os_strlen(pos); 1278252726Srpaulo u8 oi[MAX_ROAMING_CONSORTIUM_LEN]; 1279214503Srpaulo 1280252726Srpaulo struct hostapd_roaming_consortium *rc; 1281252726Srpaulo 1282252726Srpaulo if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN || 1283252726Srpaulo hexstr2bin(pos, oi, len / 2)) { 1284252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium " 1285252726Srpaulo "'%s'", line, pos); 1286252726Srpaulo return -1; 1287214503Srpaulo } 1288252726Srpaulo len /= 2; 1289214503Srpaulo 1290252726Srpaulo rc = os_realloc_array(bss->roaming_consortium, 1291252726Srpaulo bss->roaming_consortium_count + 1, 1292252726Srpaulo sizeof(struct hostapd_roaming_consortium)); 1293252726Srpaulo if (rc == NULL) 1294252726Srpaulo return -1; 1295252726Srpaulo 1296252726Srpaulo os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len); 1297252726Srpaulo rc[bss->roaming_consortium_count].len = len; 1298252726Srpaulo 1299252726Srpaulo bss->roaming_consortium = rc; 1300252726Srpaulo bss->roaming_consortium_count++; 1301252726Srpaulo 1302252726Srpaulo return 0; 1303252726Srpaulo} 1304252726Srpaulo 1305252726Srpaulo 1306252726Srpaulostatic int parse_lang_string(struct hostapd_lang_string **array, 1307252726Srpaulo unsigned int *count, char *pos) 1308252726Srpaulo{ 1309252726Srpaulo char *sep; 1310252726Srpaulo size_t clen, nlen; 1311252726Srpaulo struct hostapd_lang_string *ls; 1312252726Srpaulo 1313252726Srpaulo sep = os_strchr(pos, ':'); 1314252726Srpaulo if (sep == NULL) 1315252726Srpaulo return -1; 1316252726Srpaulo *sep++ = '\0'; 1317252726Srpaulo 1318252726Srpaulo clen = os_strlen(pos); 1319252726Srpaulo if (clen < 2) 1320252726Srpaulo return -1; 1321252726Srpaulo nlen = os_strlen(sep); 1322252726Srpaulo if (nlen > 252) 1323252726Srpaulo return -1; 1324252726Srpaulo 1325252726Srpaulo ls = os_realloc_array(*array, *count + 1, 1326252726Srpaulo sizeof(struct hostapd_lang_string)); 1327252726Srpaulo if (ls == NULL) 1328252726Srpaulo return -1; 1329252726Srpaulo 1330252726Srpaulo *array = ls; 1331252726Srpaulo ls = &(*array)[*count]; 1332252726Srpaulo (*count)++; 1333252726Srpaulo 1334252726Srpaulo os_memset(ls->lang, 0, sizeof(ls->lang)); 1335252726Srpaulo os_memcpy(ls->lang, pos, clen); 1336252726Srpaulo ls->name_len = nlen; 1337252726Srpaulo os_memcpy(ls->name, sep, nlen); 1338252726Srpaulo 1339252726Srpaulo return 0; 1340252726Srpaulo} 1341252726Srpaulo 1342252726Srpaulo 1343252726Srpaulostatic int parse_venue_name(struct hostapd_bss_config *bss, char *pos, 1344252726Srpaulo int line) 1345252726Srpaulo{ 1346252726Srpaulo if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) { 1347252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'", 1348252726Srpaulo line, pos); 1349252726Srpaulo return -1; 1350214503Srpaulo } 1351252726Srpaulo return 0; 1352252726Srpaulo} 1353214503Srpaulo 1354252726Srpaulo 1355252726Srpaulostatic int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf, 1356252726Srpaulo int line) 1357252726Srpaulo{ 1358252726Srpaulo size_t count; 1359252726Srpaulo char *pos; 1360252726Srpaulo u8 *info = NULL, *ipos; 1361252726Srpaulo 1362252726Srpaulo /* format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] */ 1363252726Srpaulo 1364252726Srpaulo count = 1; 1365252726Srpaulo for (pos = buf; *pos; pos++) { 1366252726Srpaulo if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',') 1367252726Srpaulo goto fail; 1368252726Srpaulo if (*pos == ';') 1369252726Srpaulo count++; 1370214503Srpaulo } 1371252726Srpaulo if (1 + count * 3 > 0x7f) 1372252726Srpaulo goto fail; 1373214503Srpaulo 1374252726Srpaulo info = os_zalloc(2 + 3 + count * 3); 1375252726Srpaulo if (info == NULL) 1376252726Srpaulo return -1; 1377214503Srpaulo 1378252726Srpaulo ipos = info; 1379252726Srpaulo *ipos++ = 0; /* GUD - Version 1 */ 1380252726Srpaulo *ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */ 1381252726Srpaulo *ipos++ = 0; /* PLMN List IEI */ 1382252726Srpaulo /* ext(b8) | Length of PLMN List value contents(b7..1) */ 1383252726Srpaulo *ipos++ = 1 + count * 3; 1384252726Srpaulo *ipos++ = count; /* Number of PLMNs */ 1385214503Srpaulo 1386252726Srpaulo pos = buf; 1387252726Srpaulo while (pos && *pos) { 1388252726Srpaulo char *mcc, *mnc; 1389252726Srpaulo size_t mnc_len; 1390252726Srpaulo 1391252726Srpaulo mcc = pos; 1392252726Srpaulo mnc = os_strchr(pos, ','); 1393252726Srpaulo if (mnc == NULL) 1394252726Srpaulo goto fail; 1395252726Srpaulo *mnc++ = '\0'; 1396252726Srpaulo pos = os_strchr(mnc, ';'); 1397252726Srpaulo if (pos) 1398252726Srpaulo *pos++ = '\0'; 1399252726Srpaulo 1400252726Srpaulo mnc_len = os_strlen(mnc); 1401252726Srpaulo if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3)) 1402252726Srpaulo goto fail; 1403252726Srpaulo 1404252726Srpaulo /* BC coded MCC,MNC */ 1405252726Srpaulo /* MCC digit 2 | MCC digit 1 */ 1406252726Srpaulo *ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0'); 1407252726Srpaulo /* MNC digit 3 | MCC digit 3 */ 1408252726Srpaulo *ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) | 1409252726Srpaulo (mcc[2] - '0'); 1410252726Srpaulo /* MNC digit 2 | MNC digit 1 */ 1411252726Srpaulo *ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0'); 1412252726Srpaulo } 1413252726Srpaulo 1414252726Srpaulo os_free(bss->anqp_3gpp_cell_net); 1415252726Srpaulo bss->anqp_3gpp_cell_net = info; 1416252726Srpaulo bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count; 1417252726Srpaulo wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information", 1418252726Srpaulo bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len); 1419252726Srpaulo 1420252726Srpaulo return 0; 1421252726Srpaulo 1422252726Srpaulofail: 1423252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s", 1424252726Srpaulo line, buf); 1425252726Srpaulo os_free(info); 1426252726Srpaulo return -1; 1427252726Srpaulo} 1428252726Srpaulo 1429252726Srpaulo 1430252726Srpaulostatic int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line) 1431252726Srpaulo{ 1432252726Srpaulo struct hostapd_nai_realm_data *realm; 1433252726Srpaulo size_t i, j, len; 1434252726Srpaulo int *offsets; 1435252726Srpaulo char *pos, *end, *rpos; 1436252726Srpaulo 1437252726Srpaulo offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS, 1438252726Srpaulo sizeof(int)); 1439252726Srpaulo if (offsets == NULL) 1440252726Srpaulo return -1; 1441252726Srpaulo 1442252726Srpaulo for (i = 0; i < bss->nai_realm_count; i++) { 1443252726Srpaulo realm = &bss->nai_realm_data[i]; 1444252726Srpaulo for (j = 0; j < MAX_NAI_REALMS; j++) { 1445252726Srpaulo offsets[i * MAX_NAI_REALMS + j] = 1446252726Srpaulo realm->realm[j] ? 1447252726Srpaulo realm->realm[j] - realm->realm_buf : -1; 1448252726Srpaulo } 1449252726Srpaulo } 1450252726Srpaulo 1451252726Srpaulo realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1, 1452252726Srpaulo sizeof(struct hostapd_nai_realm_data)); 1453252726Srpaulo if (realm == NULL) { 1454252726Srpaulo os_free(offsets); 1455252726Srpaulo return -1; 1456252726Srpaulo } 1457252726Srpaulo bss->nai_realm_data = realm; 1458252726Srpaulo 1459252726Srpaulo /* patch the pointers after realloc */ 1460252726Srpaulo for (i = 0; i < bss->nai_realm_count; i++) { 1461252726Srpaulo realm = &bss->nai_realm_data[i]; 1462252726Srpaulo for (j = 0; j < MAX_NAI_REALMS; j++) { 1463252726Srpaulo int offs = offsets[i * MAX_NAI_REALMS + j]; 1464252726Srpaulo if (offs >= 0) 1465252726Srpaulo realm->realm[j] = realm->realm_buf + offs; 1466252726Srpaulo else 1467252726Srpaulo realm->realm[j] = NULL; 1468252726Srpaulo } 1469252726Srpaulo } 1470252726Srpaulo os_free(offsets); 1471252726Srpaulo 1472252726Srpaulo realm = &bss->nai_realm_data[bss->nai_realm_count]; 1473252726Srpaulo os_memset(realm, 0, sizeof(*realm)); 1474252726Srpaulo 1475252726Srpaulo pos = buf; 1476252726Srpaulo realm->encoding = atoi(pos); 1477252726Srpaulo pos = os_strchr(pos, ','); 1478252726Srpaulo if (pos == NULL) 1479252726Srpaulo goto fail; 1480252726Srpaulo pos++; 1481252726Srpaulo 1482252726Srpaulo end = os_strchr(pos, ','); 1483252726Srpaulo if (end) { 1484252726Srpaulo len = end - pos; 1485252726Srpaulo *end = '\0'; 1486252726Srpaulo } else { 1487252726Srpaulo len = os_strlen(pos); 1488252726Srpaulo } 1489252726Srpaulo 1490252726Srpaulo if (len > MAX_NAI_REALMLEN) { 1491252726Srpaulo wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d " 1492252726Srpaulo "characters)", (int) len, MAX_NAI_REALMLEN); 1493252726Srpaulo goto fail; 1494252726Srpaulo } 1495252726Srpaulo os_memcpy(realm->realm_buf, pos, len); 1496252726Srpaulo 1497252726Srpaulo if (end) 1498252726Srpaulo pos = end + 1; 1499252726Srpaulo else 1500252726Srpaulo pos = NULL; 1501252726Srpaulo 1502252726Srpaulo while (pos && *pos) { 1503252726Srpaulo struct hostapd_nai_realm_eap *eap; 1504252726Srpaulo 1505252726Srpaulo if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) { 1506252726Srpaulo wpa_printf(MSG_ERROR, "Too many EAP methods"); 1507252726Srpaulo goto fail; 1508252726Srpaulo } 1509252726Srpaulo 1510252726Srpaulo eap = &realm->eap_method[realm->eap_method_count]; 1511252726Srpaulo realm->eap_method_count++; 1512252726Srpaulo 1513252726Srpaulo end = os_strchr(pos, ','); 1514252726Srpaulo if (end == NULL) 1515252726Srpaulo end = pos + os_strlen(pos); 1516252726Srpaulo 1517252726Srpaulo eap->eap_method = atoi(pos); 1518252726Srpaulo for (;;) { 1519252726Srpaulo pos = os_strchr(pos, '['); 1520252726Srpaulo if (pos == NULL || pos > end) 1521214503Srpaulo break; 1522252726Srpaulo pos++; 1523252726Srpaulo if (eap->num_auths >= MAX_NAI_AUTH_TYPES) { 1524252726Srpaulo wpa_printf(MSG_ERROR, "Too many auth params"); 1525252726Srpaulo goto fail; 1526214503Srpaulo } 1527252726Srpaulo eap->auth_id[eap->num_auths] = atoi(pos); 1528252726Srpaulo pos = os_strchr(pos, ':'); 1529252726Srpaulo if (pos == NULL || pos > end) 1530252726Srpaulo goto fail; 1531214503Srpaulo pos++; 1532252726Srpaulo eap->auth_val[eap->num_auths] = atoi(pos); 1533252726Srpaulo pos = os_strchr(pos, ']'); 1534252726Srpaulo if (pos == NULL || pos > end) 1535252726Srpaulo goto fail; 1536252726Srpaulo pos++; 1537252726Srpaulo eap->num_auths++; 1538214503Srpaulo } 1539214503Srpaulo 1540252726Srpaulo if (*end != ',') 1541252726Srpaulo break; 1542252726Srpaulo 1543252726Srpaulo pos = end + 1; 1544252726Srpaulo } 1545252726Srpaulo 1546252726Srpaulo /* Split realm list into null terminated realms */ 1547252726Srpaulo rpos = realm->realm_buf; 1548252726Srpaulo i = 0; 1549252726Srpaulo while (*rpos) { 1550252726Srpaulo if (i >= MAX_NAI_REALMS) { 1551252726Srpaulo wpa_printf(MSG_ERROR, "Too many realms"); 1552252726Srpaulo goto fail; 1553214503Srpaulo } 1554252726Srpaulo realm->realm[i++] = rpos; 1555252726Srpaulo rpos = os_strchr(rpos, ';'); 1556252726Srpaulo if (rpos == NULL) 1557252726Srpaulo break; 1558252726Srpaulo *rpos++ = '\0'; 1559252726Srpaulo } 1560214503Srpaulo 1561252726Srpaulo bss->nai_realm_count++; 1562252726Srpaulo 1563252726Srpaulo return 0; 1564252726Srpaulo 1565252726Srpaulofail: 1566252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf); 1567252726Srpaulo return -1; 1568252726Srpaulo} 1569252726Srpaulo 1570252726Srpaulo#endif /* CONFIG_INTERWORKING */ 1571252726Srpaulo 1572252726Srpaulo 1573252726Srpaulo#ifdef CONFIG_HS20 1574252726Srpaulostatic int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf, 1575252726Srpaulo int line) 1576252726Srpaulo{ 1577252726Srpaulo u8 *conn_cap; 1578252726Srpaulo char *pos; 1579252726Srpaulo 1580252726Srpaulo if (bss->hs20_connection_capability_len >= 0xfff0) 1581252726Srpaulo return -1; 1582252726Srpaulo 1583252726Srpaulo conn_cap = os_realloc(bss->hs20_connection_capability, 1584252726Srpaulo bss->hs20_connection_capability_len + 4); 1585252726Srpaulo if (conn_cap == NULL) 1586252726Srpaulo return -1; 1587252726Srpaulo 1588252726Srpaulo bss->hs20_connection_capability = conn_cap; 1589252726Srpaulo conn_cap += bss->hs20_connection_capability_len; 1590252726Srpaulo pos = buf; 1591252726Srpaulo conn_cap[0] = atoi(pos); 1592252726Srpaulo pos = os_strchr(pos, ':'); 1593252726Srpaulo if (pos == NULL) 1594252726Srpaulo return -1; 1595252726Srpaulo pos++; 1596252726Srpaulo WPA_PUT_LE16(conn_cap + 1, atoi(pos)); 1597252726Srpaulo pos = os_strchr(pos, ':'); 1598252726Srpaulo if (pos == NULL) 1599252726Srpaulo return -1; 1600252726Srpaulo pos++; 1601252726Srpaulo conn_cap[3] = atoi(pos); 1602252726Srpaulo bss->hs20_connection_capability_len += 4; 1603252726Srpaulo 1604252726Srpaulo return 0; 1605252726Srpaulo} 1606252726Srpaulo 1607252726Srpaulo 1608252726Srpaulostatic int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf, 1609252726Srpaulo int line) 1610252726Srpaulo{ 1611252726Srpaulo u8 *wan_metrics; 1612252726Srpaulo char *pos; 1613252726Srpaulo 1614252726Srpaulo /* <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> */ 1615252726Srpaulo 1616252726Srpaulo wan_metrics = os_zalloc(13); 1617252726Srpaulo if (wan_metrics == NULL) 1618252726Srpaulo return -1; 1619252726Srpaulo 1620252726Srpaulo pos = buf; 1621252726Srpaulo /* WAN Info */ 1622252726Srpaulo if (hexstr2bin(pos, wan_metrics, 1) < 0) 1623252726Srpaulo goto fail; 1624252726Srpaulo pos += 2; 1625252726Srpaulo if (*pos != ':') 1626252726Srpaulo goto fail; 1627252726Srpaulo pos++; 1628252726Srpaulo 1629252726Srpaulo /* Downlink Speed */ 1630252726Srpaulo WPA_PUT_LE32(wan_metrics + 1, atoi(pos)); 1631252726Srpaulo pos = os_strchr(pos, ':'); 1632252726Srpaulo if (pos == NULL) 1633252726Srpaulo goto fail; 1634252726Srpaulo pos++; 1635252726Srpaulo 1636252726Srpaulo /* Uplink Speed */ 1637252726Srpaulo WPA_PUT_LE32(wan_metrics + 5, atoi(pos)); 1638252726Srpaulo pos = os_strchr(pos, ':'); 1639252726Srpaulo if (pos == NULL) 1640252726Srpaulo goto fail; 1641252726Srpaulo pos++; 1642252726Srpaulo 1643252726Srpaulo /* Downlink Load */ 1644252726Srpaulo wan_metrics[9] = atoi(pos); 1645252726Srpaulo pos = os_strchr(pos, ':'); 1646252726Srpaulo if (pos == NULL) 1647252726Srpaulo goto fail; 1648252726Srpaulo pos++; 1649252726Srpaulo 1650252726Srpaulo /* Uplink Load */ 1651252726Srpaulo wan_metrics[10] = atoi(pos); 1652252726Srpaulo pos = os_strchr(pos, ':'); 1653252726Srpaulo if (pos == NULL) 1654252726Srpaulo goto fail; 1655252726Srpaulo pos++; 1656252726Srpaulo 1657252726Srpaulo /* LMD */ 1658252726Srpaulo WPA_PUT_LE16(wan_metrics + 11, atoi(pos)); 1659252726Srpaulo 1660252726Srpaulo os_free(bss->hs20_wan_metrics); 1661252726Srpaulo bss->hs20_wan_metrics = wan_metrics; 1662252726Srpaulo 1663252726Srpaulo return 0; 1664252726Srpaulo 1665252726Srpaulofail: 1666252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'", 1667252726Srpaulo line, pos); 1668252726Srpaulo os_free(wan_metrics); 1669252726Srpaulo return -1; 1670252726Srpaulo} 1671252726Srpaulo 1672252726Srpaulo 1673252726Srpaulostatic int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss, 1674252726Srpaulo char *pos, int line) 1675252726Srpaulo{ 1676252726Srpaulo if (parse_lang_string(&bss->hs20_oper_friendly_name, 1677252726Srpaulo &bss->hs20_oper_friendly_name_count, pos)) { 1678252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 1679252726Srpaulo "hs20_oper_friendly_name '%s'", line, pos); 1680252726Srpaulo return -1; 1681252726Srpaulo } 1682252726Srpaulo return 0; 1683252726Srpaulo} 1684252726Srpaulo#endif /* CONFIG_HS20 */ 1685252726Srpaulo 1686252726Srpaulo 1687252726Srpaulo#ifdef CONFIG_WPS_NFC 1688252726Srpaulostatic struct wpabuf * hostapd_parse_bin(const char *buf) 1689252726Srpaulo{ 1690252726Srpaulo size_t len; 1691252726Srpaulo struct wpabuf *ret; 1692252726Srpaulo 1693252726Srpaulo len = os_strlen(buf); 1694252726Srpaulo if (len & 0x01) 1695252726Srpaulo return NULL; 1696252726Srpaulo len /= 2; 1697252726Srpaulo 1698252726Srpaulo ret = wpabuf_alloc(len); 1699252726Srpaulo if (ret == NULL) 1700252726Srpaulo return NULL; 1701252726Srpaulo 1702252726Srpaulo if (hexstr2bin(buf, wpabuf_put(ret, len), len)) { 1703252726Srpaulo wpabuf_free(ret); 1704252726Srpaulo return NULL; 1705252726Srpaulo } 1706252726Srpaulo 1707252726Srpaulo return ret; 1708252726Srpaulo} 1709252726Srpaulo#endif /* CONFIG_WPS_NFC */ 1710252726Srpaulo 1711252726Srpaulo 1712252726Srpaulostatic int hostapd_config_fill(struct hostapd_config *conf, 1713252726Srpaulo struct hostapd_bss_config *bss, 1714252726Srpaulo char *buf, char *pos, int line) 1715252726Srpaulo{ 1716252726Srpaulo int errors = 0; 1717252726Srpaulo 1718252726Srpaulo { 1719214503Srpaulo if (os_strcmp(buf, "interface") == 0) { 1720214503Srpaulo os_strlcpy(conf->bss[0].iface, pos, 1721214503Srpaulo sizeof(conf->bss[0].iface)); 1722214503Srpaulo } else if (os_strcmp(buf, "bridge") == 0) { 1723214503Srpaulo os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); 1724252726Srpaulo } else if (os_strcmp(buf, "wds_bridge") == 0) { 1725252726Srpaulo os_strlcpy(bss->wds_bridge, pos, 1726252726Srpaulo sizeof(bss->wds_bridge)); 1727214503Srpaulo } else if (os_strcmp(buf, "driver") == 0) { 1728214503Srpaulo int j; 1729214503Srpaulo /* clear to get error below if setting is invalid */ 1730214503Srpaulo conf->driver = NULL; 1731214503Srpaulo for (j = 0; wpa_drivers[j]; j++) { 1732214503Srpaulo if (os_strcmp(pos, wpa_drivers[j]->name) == 0) 1733214503Srpaulo { 1734214503Srpaulo conf->driver = wpa_drivers[j]; 1735214503Srpaulo break; 1736214503Srpaulo } 1737214503Srpaulo } 1738214503Srpaulo if (conf->driver == NULL) { 1739214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid/" 1740214503Srpaulo "unknown driver '%s'", line, pos); 1741214503Srpaulo errors++; 1742214503Srpaulo } 1743214503Srpaulo } else if (os_strcmp(buf, "debug") == 0) { 1744214503Srpaulo wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' " 1745214503Srpaulo "configuration variable is not used " 1746214503Srpaulo "anymore", line); 1747214503Srpaulo } else if (os_strcmp(buf, "logger_syslog_level") == 0) { 1748214503Srpaulo bss->logger_syslog_level = atoi(pos); 1749214503Srpaulo } else if (os_strcmp(buf, "logger_stdout_level") == 0) { 1750214503Srpaulo bss->logger_stdout_level = atoi(pos); 1751214503Srpaulo } else if (os_strcmp(buf, "logger_syslog") == 0) { 1752214503Srpaulo bss->logger_syslog = atoi(pos); 1753214503Srpaulo } else if (os_strcmp(buf, "logger_stdout") == 0) { 1754214503Srpaulo bss->logger_stdout = atoi(pos); 1755214503Srpaulo } else if (os_strcmp(buf, "dump_file") == 0) { 1756214503Srpaulo bss->dump_log_name = os_strdup(pos); 1757214503Srpaulo } else if (os_strcmp(buf, "ssid") == 0) { 1758214503Srpaulo bss->ssid.ssid_len = os_strlen(pos); 1759214503Srpaulo if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN || 1760214503Srpaulo bss->ssid.ssid_len < 1) { 1761214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid SSID " 1762214503Srpaulo "'%s'", line, pos); 1763214503Srpaulo errors++; 1764214503Srpaulo } else { 1765214503Srpaulo os_memcpy(bss->ssid.ssid, pos, 1766214503Srpaulo bss->ssid.ssid_len); 1767214503Srpaulo bss->ssid.ssid_set = 1; 1768214503Srpaulo } 1769252726Srpaulo } else if (os_strcmp(buf, "ssid2") == 0) { 1770252726Srpaulo size_t slen; 1771252726Srpaulo char *str = wpa_config_parse_string(pos, &slen); 1772252726Srpaulo if (str == NULL || slen < 1 || 1773252726Srpaulo slen > HOSTAPD_MAX_SSID_LEN) { 1774252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid SSID " 1775252726Srpaulo "'%s'", line, pos); 1776252726Srpaulo errors++; 1777252726Srpaulo } else { 1778252726Srpaulo os_memcpy(bss->ssid.ssid, str, slen); 1779252726Srpaulo bss->ssid.ssid_len = slen; 1780252726Srpaulo bss->ssid.ssid_set = 1; 1781252726Srpaulo } 1782252726Srpaulo os_free(str); 1783252726Srpaulo } else if (os_strcmp(buf, "utf8_ssid") == 0) { 1784252726Srpaulo bss->ssid.utf8_ssid = atoi(pos) > 0; 1785214503Srpaulo } else if (os_strcmp(buf, "macaddr_acl") == 0) { 1786214503Srpaulo bss->macaddr_acl = atoi(pos); 1787214503Srpaulo if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED && 1788214503Srpaulo bss->macaddr_acl != DENY_UNLESS_ACCEPTED && 1789214503Srpaulo bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { 1790214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown " 1791214503Srpaulo "macaddr_acl %d", 1792214503Srpaulo line, bss->macaddr_acl); 1793214503Srpaulo } 1794214503Srpaulo } else if (os_strcmp(buf, "accept_mac_file") == 0) { 1795214503Srpaulo if (hostapd_config_read_maclist(pos, &bss->accept_mac, 1796214503Srpaulo &bss->num_accept_mac)) 1797214503Srpaulo { 1798214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Failed to " 1799214503Srpaulo "read accept_mac_file '%s'", 1800214503Srpaulo line, pos); 1801214503Srpaulo errors++; 1802214503Srpaulo } 1803214503Srpaulo } else if (os_strcmp(buf, "deny_mac_file") == 0) { 1804214503Srpaulo if (hostapd_config_read_maclist(pos, &bss->deny_mac, 1805214503Srpaulo &bss->num_deny_mac)) { 1806214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Failed to " 1807214503Srpaulo "read deny_mac_file '%s'", 1808214503Srpaulo line, pos); 1809214503Srpaulo errors++; 1810214503Srpaulo } 1811214503Srpaulo } else if (os_strcmp(buf, "wds_sta") == 0) { 1812214503Srpaulo bss->wds_sta = atoi(pos); 1813252726Srpaulo } else if (os_strcmp(buf, "ap_isolate") == 0) { 1814252726Srpaulo bss->isolate = atoi(pos); 1815214503Srpaulo } else if (os_strcmp(buf, "ap_max_inactivity") == 0) { 1816214503Srpaulo bss->ap_max_inactivity = atoi(pos); 1817252726Srpaulo } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) { 1818252726Srpaulo bss->skip_inactivity_poll = atoi(pos); 1819214503Srpaulo } else if (os_strcmp(buf, "country_code") == 0) { 1820214503Srpaulo os_memcpy(conf->country, pos, 2); 1821214503Srpaulo /* FIX: make this configurable */ 1822214503Srpaulo conf->country[2] = ' '; 1823214503Srpaulo } else if (os_strcmp(buf, "ieee80211d") == 0) { 1824214503Srpaulo conf->ieee80211d = atoi(pos); 1825214503Srpaulo } else if (os_strcmp(buf, "ieee8021x") == 0) { 1826214503Srpaulo bss->ieee802_1x = atoi(pos); 1827214503Srpaulo } else if (os_strcmp(buf, "eapol_version") == 0) { 1828214503Srpaulo bss->eapol_version = atoi(pos); 1829214503Srpaulo if (bss->eapol_version < 1 || 1830214503Srpaulo bss->eapol_version > 2) { 1831214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL " 1832214503Srpaulo "version (%d): '%s'.", 1833214503Srpaulo line, bss->eapol_version, pos); 1834214503Srpaulo errors++; 1835214503Srpaulo } else 1836214503Srpaulo wpa_printf(MSG_DEBUG, "eapol_version=%d", 1837214503Srpaulo bss->eapol_version); 1838214503Srpaulo#ifdef EAP_SERVER 1839214503Srpaulo } else if (os_strcmp(buf, "eap_authenticator") == 0) { 1840214503Srpaulo bss->eap_server = atoi(pos); 1841214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: obsolete " 1842214503Srpaulo "eap_authenticator used; this has been " 1843214503Srpaulo "renamed to eap_server", line); 1844214503Srpaulo } else if (os_strcmp(buf, "eap_server") == 0) { 1845214503Srpaulo bss->eap_server = atoi(pos); 1846214503Srpaulo } else if (os_strcmp(buf, "eap_user_file") == 0) { 1847214503Srpaulo if (hostapd_config_read_eap_user(pos, bss)) 1848214503Srpaulo errors++; 1849214503Srpaulo } else if (os_strcmp(buf, "ca_cert") == 0) { 1850214503Srpaulo os_free(bss->ca_cert); 1851214503Srpaulo bss->ca_cert = os_strdup(pos); 1852214503Srpaulo } else if (os_strcmp(buf, "server_cert") == 0) { 1853214503Srpaulo os_free(bss->server_cert); 1854214503Srpaulo bss->server_cert = os_strdup(pos); 1855214503Srpaulo } else if (os_strcmp(buf, "private_key") == 0) { 1856214503Srpaulo os_free(bss->private_key); 1857214503Srpaulo bss->private_key = os_strdup(pos); 1858214503Srpaulo } else if (os_strcmp(buf, "private_key_passwd") == 0) { 1859214503Srpaulo os_free(bss->private_key_passwd); 1860214503Srpaulo bss->private_key_passwd = os_strdup(pos); 1861214503Srpaulo } else if (os_strcmp(buf, "check_crl") == 0) { 1862214503Srpaulo bss->check_crl = atoi(pos); 1863214503Srpaulo } else if (os_strcmp(buf, "dh_file") == 0) { 1864214503Srpaulo os_free(bss->dh_file); 1865214503Srpaulo bss->dh_file = os_strdup(pos); 1866252726Srpaulo } else if (os_strcmp(buf, "fragment_size") == 0) { 1867252726Srpaulo bss->fragment_size = atoi(pos); 1868214503Srpaulo#ifdef EAP_SERVER_FAST 1869214503Srpaulo } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) { 1870214503Srpaulo os_free(bss->pac_opaque_encr_key); 1871214503Srpaulo bss->pac_opaque_encr_key = os_malloc(16); 1872214503Srpaulo if (bss->pac_opaque_encr_key == NULL) { 1873214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: No memory for " 1874214503Srpaulo "pac_opaque_encr_key", line); 1875214503Srpaulo errors++; 1876214503Srpaulo } else if (hexstr2bin(pos, bss->pac_opaque_encr_key, 1877214503Srpaulo 16)) { 1878214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 1879214503Srpaulo "pac_opaque_encr_key", line); 1880214503Srpaulo errors++; 1881214503Srpaulo } 1882214503Srpaulo } else if (os_strcmp(buf, "eap_fast_a_id") == 0) { 1883214503Srpaulo size_t idlen = os_strlen(pos); 1884214503Srpaulo if (idlen & 1) { 1885214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 1886214503Srpaulo "eap_fast_a_id", line); 1887214503Srpaulo errors++; 1888214503Srpaulo } else { 1889214503Srpaulo os_free(bss->eap_fast_a_id); 1890214503Srpaulo bss->eap_fast_a_id = os_malloc(idlen / 2); 1891214503Srpaulo if (bss->eap_fast_a_id == NULL || 1892214503Srpaulo hexstr2bin(pos, bss->eap_fast_a_id, 1893214503Srpaulo idlen / 2)) { 1894214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: " 1895214503Srpaulo "Failed to parse " 1896214503Srpaulo "eap_fast_a_id", line); 1897214503Srpaulo errors++; 1898214503Srpaulo } else 1899214503Srpaulo bss->eap_fast_a_id_len = idlen / 2; 1900214503Srpaulo } 1901214503Srpaulo } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) { 1902214503Srpaulo os_free(bss->eap_fast_a_id_info); 1903214503Srpaulo bss->eap_fast_a_id_info = os_strdup(pos); 1904214503Srpaulo } else if (os_strcmp(buf, "eap_fast_prov") == 0) { 1905214503Srpaulo bss->eap_fast_prov = atoi(pos); 1906214503Srpaulo } else if (os_strcmp(buf, "pac_key_lifetime") == 0) { 1907214503Srpaulo bss->pac_key_lifetime = atoi(pos); 1908214503Srpaulo } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) { 1909214503Srpaulo bss->pac_key_refresh_time = atoi(pos); 1910214503Srpaulo#endif /* EAP_SERVER_FAST */ 1911214503Srpaulo#ifdef EAP_SERVER_SIM 1912214503Srpaulo } else if (os_strcmp(buf, "eap_sim_db") == 0) { 1913214503Srpaulo os_free(bss->eap_sim_db); 1914214503Srpaulo bss->eap_sim_db = os_strdup(pos); 1915214503Srpaulo } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) { 1916214503Srpaulo bss->eap_sim_aka_result_ind = atoi(pos); 1917214503Srpaulo#endif /* EAP_SERVER_SIM */ 1918214503Srpaulo#ifdef EAP_SERVER_TNC 1919214503Srpaulo } else if (os_strcmp(buf, "tnc") == 0) { 1920214503Srpaulo bss->tnc = atoi(pos); 1921214503Srpaulo#endif /* EAP_SERVER_TNC */ 1922252726Srpaulo#ifdef EAP_SERVER_PWD 1923252726Srpaulo } else if (os_strcmp(buf, "pwd_group") == 0) { 1924252726Srpaulo bss->pwd_group = atoi(pos); 1925252726Srpaulo#endif /* EAP_SERVER_PWD */ 1926214503Srpaulo#endif /* EAP_SERVER */ 1927214503Srpaulo } else if (os_strcmp(buf, "eap_message") == 0) { 1928214503Srpaulo char *term; 1929214503Srpaulo bss->eap_req_id_text = os_strdup(pos); 1930214503Srpaulo if (bss->eap_req_id_text == NULL) { 1931214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Failed to " 1932214503Srpaulo "allocate memory for " 1933214503Srpaulo "eap_req_id_text", line); 1934214503Srpaulo errors++; 1935252726Srpaulo return errors; 1936214503Srpaulo } 1937214503Srpaulo bss->eap_req_id_text_len = 1938214503Srpaulo os_strlen(bss->eap_req_id_text); 1939214503Srpaulo term = os_strstr(bss->eap_req_id_text, "\\0"); 1940214503Srpaulo if (term) { 1941214503Srpaulo *term++ = '\0'; 1942214503Srpaulo os_memmove(term, term + 1, 1943214503Srpaulo bss->eap_req_id_text_len - 1944214503Srpaulo (term - bss->eap_req_id_text) - 1); 1945214503Srpaulo bss->eap_req_id_text_len--; 1946214503Srpaulo } 1947214503Srpaulo } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) { 1948214503Srpaulo bss->default_wep_key_len = atoi(pos); 1949214503Srpaulo if (bss->default_wep_key_len > 13) { 1950214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid WEP " 1951214503Srpaulo "key len %lu (= %lu bits)", line, 1952214503Srpaulo (unsigned long) 1953214503Srpaulo bss->default_wep_key_len, 1954214503Srpaulo (unsigned long) 1955214503Srpaulo bss->default_wep_key_len * 8); 1956214503Srpaulo errors++; 1957214503Srpaulo } 1958214503Srpaulo } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) { 1959214503Srpaulo bss->individual_wep_key_len = atoi(pos); 1960214503Srpaulo if (bss->individual_wep_key_len < 0 || 1961214503Srpaulo bss->individual_wep_key_len > 13) { 1962214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid WEP " 1963214503Srpaulo "key len %d (= %d bits)", line, 1964214503Srpaulo bss->individual_wep_key_len, 1965214503Srpaulo bss->individual_wep_key_len * 8); 1966214503Srpaulo errors++; 1967214503Srpaulo } 1968214503Srpaulo } else if (os_strcmp(buf, "wep_rekey_period") == 0) { 1969214503Srpaulo bss->wep_rekeying_period = atoi(pos); 1970214503Srpaulo if (bss->wep_rekeying_period < 0) { 1971214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 1972214503Srpaulo "period %d", 1973214503Srpaulo line, bss->wep_rekeying_period); 1974214503Srpaulo errors++; 1975214503Srpaulo } 1976214503Srpaulo } else if (os_strcmp(buf, "eap_reauth_period") == 0) { 1977214503Srpaulo bss->eap_reauth_period = atoi(pos); 1978214503Srpaulo if (bss->eap_reauth_period < 0) { 1979214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 1980214503Srpaulo "period %d", 1981214503Srpaulo line, bss->eap_reauth_period); 1982214503Srpaulo errors++; 1983214503Srpaulo } 1984214503Srpaulo } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) { 1985214503Srpaulo bss->eapol_key_index_workaround = atoi(pos); 1986214503Srpaulo#ifdef CONFIG_IAPP 1987214503Srpaulo } else if (os_strcmp(buf, "iapp_interface") == 0) { 1988214503Srpaulo bss->ieee802_11f = 1; 1989214503Srpaulo os_strlcpy(bss->iapp_iface, pos, 1990214503Srpaulo sizeof(bss->iapp_iface)); 1991214503Srpaulo#endif /* CONFIG_IAPP */ 1992214503Srpaulo } else if (os_strcmp(buf, "own_ip_addr") == 0) { 1993214503Srpaulo if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) { 1994214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid IP " 1995214503Srpaulo "address '%s'", line, pos); 1996214503Srpaulo errors++; 1997214503Srpaulo } 1998214503Srpaulo } else if (os_strcmp(buf, "nas_identifier") == 0) { 1999214503Srpaulo bss->nas_identifier = os_strdup(pos); 2000214503Srpaulo#ifndef CONFIG_NO_RADIUS 2001214503Srpaulo } else if (os_strcmp(buf, "auth_server_addr") == 0) { 2002214503Srpaulo if (hostapd_config_read_radius_addr( 2003214503Srpaulo &bss->radius->auth_servers, 2004214503Srpaulo &bss->radius->num_auth_servers, pos, 1812, 2005214503Srpaulo &bss->radius->auth_server)) { 2006214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid IP " 2007214503Srpaulo "address '%s'", line, pos); 2008214503Srpaulo errors++; 2009214503Srpaulo } 2010214503Srpaulo } else if (bss->radius->auth_server && 2011214503Srpaulo os_strcmp(buf, "auth_server_port") == 0) { 2012214503Srpaulo bss->radius->auth_server->port = atoi(pos); 2013214503Srpaulo } else if (bss->radius->auth_server && 2014214503Srpaulo os_strcmp(buf, "auth_server_shared_secret") == 0) { 2015214503Srpaulo int len = os_strlen(pos); 2016214503Srpaulo if (len == 0) { 2017214503Srpaulo /* RFC 2865, Ch. 3 */ 2018214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: empty shared " 2019214503Srpaulo "secret is not allowed.", line); 2020214503Srpaulo errors++; 2021214503Srpaulo } 2022214503Srpaulo bss->radius->auth_server->shared_secret = 2023214503Srpaulo (u8 *) os_strdup(pos); 2024214503Srpaulo bss->radius->auth_server->shared_secret_len = len; 2025214503Srpaulo } else if (os_strcmp(buf, "acct_server_addr") == 0) { 2026214503Srpaulo if (hostapd_config_read_radius_addr( 2027214503Srpaulo &bss->radius->acct_servers, 2028214503Srpaulo &bss->radius->num_acct_servers, pos, 1813, 2029214503Srpaulo &bss->radius->acct_server)) { 2030214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid IP " 2031214503Srpaulo "address '%s'", line, pos); 2032214503Srpaulo errors++; 2033214503Srpaulo } 2034214503Srpaulo } else if (bss->radius->acct_server && 2035214503Srpaulo os_strcmp(buf, "acct_server_port") == 0) { 2036214503Srpaulo bss->radius->acct_server->port = atoi(pos); 2037214503Srpaulo } else if (bss->radius->acct_server && 2038214503Srpaulo os_strcmp(buf, "acct_server_shared_secret") == 0) { 2039214503Srpaulo int len = os_strlen(pos); 2040214503Srpaulo if (len == 0) { 2041214503Srpaulo /* RFC 2865, Ch. 3 */ 2042214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: empty shared " 2043214503Srpaulo "secret is not allowed.", line); 2044214503Srpaulo errors++; 2045214503Srpaulo } 2046214503Srpaulo bss->radius->acct_server->shared_secret = 2047214503Srpaulo (u8 *) os_strdup(pos); 2048214503Srpaulo bss->radius->acct_server->shared_secret_len = len; 2049214503Srpaulo } else if (os_strcmp(buf, "radius_retry_primary_interval") == 2050214503Srpaulo 0) { 2051214503Srpaulo bss->radius->retry_primary_interval = atoi(pos); 2052214503Srpaulo } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) 2053214503Srpaulo { 2054214503Srpaulo bss->acct_interim_interval = atoi(pos); 2055252726Srpaulo } else if (os_strcmp(buf, "radius_request_cui") == 0) { 2056252726Srpaulo bss->radius_request_cui = atoi(pos); 2057252726Srpaulo } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) { 2058252726Srpaulo struct hostapd_radius_attr *attr, *a; 2059252726Srpaulo attr = hostapd_parse_radius_attr(pos); 2060252726Srpaulo if (attr == NULL) { 2061252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2062252726Srpaulo "radius_auth_req_attr", line); 2063252726Srpaulo errors++; 2064252726Srpaulo } else if (bss->radius_auth_req_attr == NULL) { 2065252726Srpaulo bss->radius_auth_req_attr = attr; 2066252726Srpaulo } else { 2067252726Srpaulo a = bss->radius_auth_req_attr; 2068252726Srpaulo while (a->next) 2069252726Srpaulo a = a->next; 2070252726Srpaulo a->next = attr; 2071252726Srpaulo } 2072252726Srpaulo } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) { 2073252726Srpaulo struct hostapd_radius_attr *attr, *a; 2074252726Srpaulo attr = hostapd_parse_radius_attr(pos); 2075252726Srpaulo if (attr == NULL) { 2076252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2077252726Srpaulo "radius_acct_req_attr", line); 2078252726Srpaulo errors++; 2079252726Srpaulo } else if (bss->radius_acct_req_attr == NULL) { 2080252726Srpaulo bss->radius_acct_req_attr = attr; 2081252726Srpaulo } else { 2082252726Srpaulo a = bss->radius_acct_req_attr; 2083252726Srpaulo while (a->next) 2084252726Srpaulo a = a->next; 2085252726Srpaulo a->next = attr; 2086252726Srpaulo } 2087252726Srpaulo } else if (os_strcmp(buf, "radius_das_port") == 0) { 2088252726Srpaulo bss->radius_das_port = atoi(pos); 2089252726Srpaulo } else if (os_strcmp(buf, "radius_das_client") == 0) { 2090252726Srpaulo if (hostapd_parse_das_client(bss, pos) < 0) { 2091252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2092252726Srpaulo "DAS client", line); 2093252726Srpaulo errors++; 2094252726Srpaulo } 2095252726Srpaulo } else if (os_strcmp(buf, "radius_das_time_window") == 0) { 2096252726Srpaulo bss->radius_das_time_window = atoi(pos); 2097252726Srpaulo } else if (os_strcmp(buf, "radius_das_require_event_timestamp") 2098252726Srpaulo == 0) { 2099252726Srpaulo bss->radius_das_require_event_timestamp = atoi(pos); 2100214503Srpaulo#endif /* CONFIG_NO_RADIUS */ 2101214503Srpaulo } else if (os_strcmp(buf, "auth_algs") == 0) { 2102214503Srpaulo bss->auth_algs = atoi(pos); 2103214503Srpaulo if (bss->auth_algs == 0) { 2104214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: no " 2105214503Srpaulo "authentication algorithms allowed", 2106214503Srpaulo line); 2107214503Srpaulo errors++; 2108214503Srpaulo } 2109214503Srpaulo } else if (os_strcmp(buf, "max_num_sta") == 0) { 2110214503Srpaulo bss->max_num_sta = atoi(pos); 2111214503Srpaulo if (bss->max_num_sta < 0 || 2112214503Srpaulo bss->max_num_sta > MAX_STA_COUNT) { 2113214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 2114214503Srpaulo "max_num_sta=%d; allowed range " 2115214503Srpaulo "0..%d", line, bss->max_num_sta, 2116214503Srpaulo MAX_STA_COUNT); 2117214503Srpaulo errors++; 2118214503Srpaulo } 2119214503Srpaulo } else if (os_strcmp(buf, "wpa") == 0) { 2120214503Srpaulo bss->wpa = atoi(pos); 2121214503Srpaulo } else if (os_strcmp(buf, "wpa_group_rekey") == 0) { 2122214503Srpaulo bss->wpa_group_rekey = atoi(pos); 2123214503Srpaulo } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) { 2124214503Srpaulo bss->wpa_strict_rekey = atoi(pos); 2125214503Srpaulo } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) { 2126214503Srpaulo bss->wpa_gmk_rekey = atoi(pos); 2127214503Srpaulo } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) { 2128214503Srpaulo bss->wpa_ptk_rekey = atoi(pos); 2129214503Srpaulo } else if (os_strcmp(buf, "wpa_passphrase") == 0) { 2130214503Srpaulo int len = os_strlen(pos); 2131214503Srpaulo if (len < 8 || len > 63) { 2132214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid WPA " 2133214503Srpaulo "passphrase length %d (expected " 2134214503Srpaulo "8..63)", line, len); 2135214503Srpaulo errors++; 2136214503Srpaulo } else { 2137214503Srpaulo os_free(bss->ssid.wpa_passphrase); 2138214503Srpaulo bss->ssid.wpa_passphrase = os_strdup(pos); 2139252726Srpaulo os_free(bss->ssid.wpa_psk); 2140252726Srpaulo bss->ssid.wpa_psk = NULL; 2141214503Srpaulo } 2142214503Srpaulo } else if (os_strcmp(buf, "wpa_psk") == 0) { 2143214503Srpaulo os_free(bss->ssid.wpa_psk); 2144214503Srpaulo bss->ssid.wpa_psk = 2145214503Srpaulo os_zalloc(sizeof(struct hostapd_wpa_psk)); 2146214503Srpaulo if (bss->ssid.wpa_psk == NULL) 2147214503Srpaulo errors++; 2148214503Srpaulo else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk, 2149214503Srpaulo PMK_LEN) || 2150214503Srpaulo pos[PMK_LEN * 2] != '\0') { 2151214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid PSK " 2152214503Srpaulo "'%s'.", line, pos); 2153214503Srpaulo errors++; 2154214503Srpaulo } else { 2155214503Srpaulo bss->ssid.wpa_psk->group = 1; 2156252726Srpaulo os_free(bss->ssid.wpa_passphrase); 2157252726Srpaulo bss->ssid.wpa_passphrase = NULL; 2158214503Srpaulo } 2159214503Srpaulo } else if (os_strcmp(buf, "wpa_psk_file") == 0) { 2160214503Srpaulo os_free(bss->ssid.wpa_psk_file); 2161214503Srpaulo bss->ssid.wpa_psk_file = os_strdup(pos); 2162214503Srpaulo if (!bss->ssid.wpa_psk_file) { 2163214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: allocation " 2164214503Srpaulo "failed", line); 2165214503Srpaulo errors++; 2166214503Srpaulo } 2167214503Srpaulo } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) { 2168214503Srpaulo bss->wpa_key_mgmt = 2169214503Srpaulo hostapd_config_parse_key_mgmt(line, pos); 2170214503Srpaulo if (bss->wpa_key_mgmt == -1) 2171214503Srpaulo errors++; 2172252726Srpaulo } else if (os_strcmp(buf, "wpa_psk_radius") == 0) { 2173252726Srpaulo bss->wpa_psk_radius = atoi(pos); 2174252726Srpaulo if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED && 2175252726Srpaulo bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED && 2176252726Srpaulo bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) { 2177252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown " 2178252726Srpaulo "wpa_psk_radius %d", 2179252726Srpaulo line, bss->wpa_psk_radius); 2180252726Srpaulo errors++; 2181252726Srpaulo } 2182214503Srpaulo } else if (os_strcmp(buf, "wpa_pairwise") == 0) { 2183214503Srpaulo bss->wpa_pairwise = 2184214503Srpaulo hostapd_config_parse_cipher(line, pos); 2185214503Srpaulo if (bss->wpa_pairwise == -1 || 2186214503Srpaulo bss->wpa_pairwise == 0) 2187214503Srpaulo errors++; 2188214503Srpaulo else if (bss->wpa_pairwise & 2189214503Srpaulo (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | 2190214503Srpaulo WPA_CIPHER_WEP104)) { 2191214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: unsupported " 2192214503Srpaulo "pairwise cipher suite '%s'", 2193214503Srpaulo bss->wpa_pairwise, pos); 2194214503Srpaulo errors++; 2195214503Srpaulo } 2196214503Srpaulo } else if (os_strcmp(buf, "rsn_pairwise") == 0) { 2197214503Srpaulo bss->rsn_pairwise = 2198214503Srpaulo hostapd_config_parse_cipher(line, pos); 2199214503Srpaulo if (bss->rsn_pairwise == -1 || 2200214503Srpaulo bss->rsn_pairwise == 0) 2201214503Srpaulo errors++; 2202214503Srpaulo else if (bss->rsn_pairwise & 2203214503Srpaulo (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | 2204214503Srpaulo WPA_CIPHER_WEP104)) { 2205214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: unsupported " 2206214503Srpaulo "pairwise cipher suite '%s'", 2207214503Srpaulo bss->rsn_pairwise, pos); 2208214503Srpaulo errors++; 2209214503Srpaulo } 2210214503Srpaulo#ifdef CONFIG_RSN_PREAUTH 2211214503Srpaulo } else if (os_strcmp(buf, "rsn_preauth") == 0) { 2212214503Srpaulo bss->rsn_preauth = atoi(pos); 2213214503Srpaulo } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) { 2214214503Srpaulo bss->rsn_preauth_interfaces = os_strdup(pos); 2215214503Srpaulo#endif /* CONFIG_RSN_PREAUTH */ 2216214503Srpaulo#ifdef CONFIG_PEERKEY 2217214503Srpaulo } else if (os_strcmp(buf, "peerkey") == 0) { 2218214503Srpaulo bss->peerkey = atoi(pos); 2219214503Srpaulo#endif /* CONFIG_PEERKEY */ 2220214503Srpaulo#ifdef CONFIG_IEEE80211R 2221214503Srpaulo } else if (os_strcmp(buf, "mobility_domain") == 0) { 2222214503Srpaulo if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN || 2223214503Srpaulo hexstr2bin(pos, bss->mobility_domain, 2224214503Srpaulo MOBILITY_DOMAIN_ID_LEN) != 0) { 2225214503Srpaulo wpa_printf(MSG_DEBUG, "Line %d: Invalid " 2226214503Srpaulo "mobility_domain '%s'", line, pos); 2227214503Srpaulo errors++; 2228252726Srpaulo return errors; 2229214503Srpaulo } 2230214503Srpaulo } else if (os_strcmp(buf, "r1_key_holder") == 0) { 2231214503Srpaulo if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN || 2232214503Srpaulo hexstr2bin(pos, bss->r1_key_holder, 2233214503Srpaulo FT_R1KH_ID_LEN) != 0) { 2234214503Srpaulo wpa_printf(MSG_DEBUG, "Line %d: Invalid " 2235214503Srpaulo "r1_key_holder '%s'", line, pos); 2236214503Srpaulo errors++; 2237252726Srpaulo return errors; 2238214503Srpaulo } 2239214503Srpaulo } else if (os_strcmp(buf, "r0_key_lifetime") == 0) { 2240214503Srpaulo bss->r0_key_lifetime = atoi(pos); 2241214503Srpaulo } else if (os_strcmp(buf, "reassociation_deadline") == 0) { 2242214503Srpaulo bss->reassociation_deadline = atoi(pos); 2243214503Srpaulo } else if (os_strcmp(buf, "r0kh") == 0) { 2244214503Srpaulo if (add_r0kh(bss, pos) < 0) { 2245214503Srpaulo wpa_printf(MSG_DEBUG, "Line %d: Invalid " 2246214503Srpaulo "r0kh '%s'", line, pos); 2247214503Srpaulo errors++; 2248252726Srpaulo return errors; 2249214503Srpaulo } 2250214503Srpaulo } else if (os_strcmp(buf, "r1kh") == 0) { 2251214503Srpaulo if (add_r1kh(bss, pos) < 0) { 2252214503Srpaulo wpa_printf(MSG_DEBUG, "Line %d: Invalid " 2253214503Srpaulo "r1kh '%s'", line, pos); 2254214503Srpaulo errors++; 2255252726Srpaulo return errors; 2256214503Srpaulo } 2257214503Srpaulo } else if (os_strcmp(buf, "pmk_r1_push") == 0) { 2258214503Srpaulo bss->pmk_r1_push = atoi(pos); 2259252726Srpaulo } else if (os_strcmp(buf, "ft_over_ds") == 0) { 2260252726Srpaulo bss->ft_over_ds = atoi(pos); 2261214503Srpaulo#endif /* CONFIG_IEEE80211R */ 2262214503Srpaulo#ifndef CONFIG_NO_CTRL_IFACE 2263214503Srpaulo } else if (os_strcmp(buf, "ctrl_interface") == 0) { 2264214503Srpaulo os_free(bss->ctrl_interface); 2265214503Srpaulo bss->ctrl_interface = os_strdup(pos); 2266214503Srpaulo } else if (os_strcmp(buf, "ctrl_interface_group") == 0) { 2267214503Srpaulo#ifndef CONFIG_NATIVE_WINDOWS 2268214503Srpaulo struct group *grp; 2269214503Srpaulo char *endp; 2270214503Srpaulo const char *group = pos; 2271214503Srpaulo 2272214503Srpaulo grp = getgrnam(group); 2273214503Srpaulo if (grp) { 2274214503Srpaulo bss->ctrl_interface_gid = grp->gr_gid; 2275214503Srpaulo bss->ctrl_interface_gid_set = 1; 2276214503Srpaulo wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" 2277214503Srpaulo " (from group name '%s')", 2278214503Srpaulo bss->ctrl_interface_gid, group); 2279252726Srpaulo return errors; 2280214503Srpaulo } 2281214503Srpaulo 2282214503Srpaulo /* Group name not found - try to parse this as gid */ 2283214503Srpaulo bss->ctrl_interface_gid = strtol(group, &endp, 10); 2284214503Srpaulo if (*group == '\0' || *endp != '\0') { 2285214503Srpaulo wpa_printf(MSG_DEBUG, "Line %d: Invalid group " 2286214503Srpaulo "'%s'", line, group); 2287214503Srpaulo errors++; 2288252726Srpaulo return errors; 2289214503Srpaulo } 2290214503Srpaulo bss->ctrl_interface_gid_set = 1; 2291214503Srpaulo wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", 2292214503Srpaulo bss->ctrl_interface_gid); 2293214503Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */ 2294214503Srpaulo#endif /* CONFIG_NO_CTRL_IFACE */ 2295214503Srpaulo#ifdef RADIUS_SERVER 2296214503Srpaulo } else if (os_strcmp(buf, "radius_server_clients") == 0) { 2297214503Srpaulo os_free(bss->radius_server_clients); 2298214503Srpaulo bss->radius_server_clients = os_strdup(pos); 2299214503Srpaulo } else if (os_strcmp(buf, "radius_server_auth_port") == 0) { 2300214503Srpaulo bss->radius_server_auth_port = atoi(pos); 2301214503Srpaulo } else if (os_strcmp(buf, "radius_server_ipv6") == 0) { 2302214503Srpaulo bss->radius_server_ipv6 = atoi(pos); 2303214503Srpaulo#endif /* RADIUS_SERVER */ 2304214503Srpaulo } else if (os_strcmp(buf, "test_socket") == 0) { 2305214503Srpaulo os_free(bss->test_socket); 2306214503Srpaulo bss->test_socket = os_strdup(pos); 2307214503Srpaulo } else if (os_strcmp(buf, "use_pae_group_addr") == 0) { 2308214503Srpaulo bss->use_pae_group_addr = atoi(pos); 2309214503Srpaulo } else if (os_strcmp(buf, "hw_mode") == 0) { 2310214503Srpaulo if (os_strcmp(pos, "a") == 0) 2311214503Srpaulo conf->hw_mode = HOSTAPD_MODE_IEEE80211A; 2312214503Srpaulo else if (os_strcmp(pos, "b") == 0) 2313214503Srpaulo conf->hw_mode = HOSTAPD_MODE_IEEE80211B; 2314214503Srpaulo else if (os_strcmp(pos, "g") == 0) 2315214503Srpaulo conf->hw_mode = HOSTAPD_MODE_IEEE80211G; 2316252726Srpaulo else if (os_strcmp(pos, "ad") == 0) 2317252726Srpaulo conf->hw_mode = HOSTAPD_MODE_IEEE80211AD; 2318214503Srpaulo else { 2319214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown " 2320214503Srpaulo "hw_mode '%s'", line, pos); 2321214503Srpaulo errors++; 2322214503Srpaulo } 2323252726Srpaulo } else if (os_strcmp(buf, "wps_rf_bands") == 0) { 2324252726Srpaulo if (os_strcmp(pos, "a") == 0) 2325252726Srpaulo bss->wps_rf_bands = WPS_RF_50GHZ; 2326252726Srpaulo else if (os_strcmp(pos, "g") == 0 || 2327252726Srpaulo os_strcmp(pos, "b") == 0) 2328252726Srpaulo bss->wps_rf_bands = WPS_RF_24GHZ; 2329252726Srpaulo else if (os_strcmp(pos, "ag") == 0 || 2330252726Srpaulo os_strcmp(pos, "ga") == 0) 2331252726Srpaulo bss->wps_rf_bands = 2332252726Srpaulo WPS_RF_24GHZ | WPS_RF_50GHZ; 2333252726Srpaulo else { 2334252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown " 2335252726Srpaulo "wps_rf_band '%s'", line, pos); 2336252726Srpaulo errors++; 2337252726Srpaulo } 2338214503Srpaulo } else if (os_strcmp(buf, "channel") == 0) { 2339214503Srpaulo conf->channel = atoi(pos); 2340214503Srpaulo } else if (os_strcmp(buf, "beacon_int") == 0) { 2341214503Srpaulo int val = atoi(pos); 2342214503Srpaulo /* MIB defines range as 1..65535, but very small values 2343214503Srpaulo * cause problems with the current implementation. 2344214503Srpaulo * Since it is unlikely that this small numbers are 2345214503Srpaulo * useful in real life scenarios, do not allow beacon 2346214503Srpaulo * period to be set below 15 TU. */ 2347214503Srpaulo if (val < 15 || val > 65535) { 2348214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2349214503Srpaulo "beacon_int %d (expected " 2350214503Srpaulo "15..65535)", line, val); 2351214503Srpaulo errors++; 2352214503Srpaulo } else 2353214503Srpaulo conf->beacon_int = val; 2354214503Srpaulo } else if (os_strcmp(buf, "dtim_period") == 0) { 2355214503Srpaulo bss->dtim_period = atoi(pos); 2356214503Srpaulo if (bss->dtim_period < 1 || bss->dtim_period > 255) { 2357214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2358214503Srpaulo "dtim_period %d", 2359214503Srpaulo line, bss->dtim_period); 2360214503Srpaulo errors++; 2361214503Srpaulo } 2362214503Srpaulo } else if (os_strcmp(buf, "rts_threshold") == 0) { 2363214503Srpaulo conf->rts_threshold = atoi(pos); 2364214503Srpaulo if (conf->rts_threshold < 0 || 2365214503Srpaulo conf->rts_threshold > 2347) { 2366214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2367214503Srpaulo "rts_threshold %d", 2368214503Srpaulo line, conf->rts_threshold); 2369214503Srpaulo errors++; 2370214503Srpaulo } 2371214503Srpaulo } else if (os_strcmp(buf, "fragm_threshold") == 0) { 2372214503Srpaulo conf->fragm_threshold = atoi(pos); 2373214503Srpaulo if (conf->fragm_threshold < 256 || 2374214503Srpaulo conf->fragm_threshold > 2346) { 2375214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2376214503Srpaulo "fragm_threshold %d", 2377214503Srpaulo line, conf->fragm_threshold); 2378214503Srpaulo errors++; 2379214503Srpaulo } 2380214503Srpaulo } else if (os_strcmp(buf, "send_probe_response") == 0) { 2381214503Srpaulo int val = atoi(pos); 2382214503Srpaulo if (val != 0 && val != 1) { 2383214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2384214503Srpaulo "send_probe_response %d (expected " 2385214503Srpaulo "0 or 1)", line, val); 2386214503Srpaulo } else 2387214503Srpaulo conf->send_probe_response = val; 2388214503Srpaulo } else if (os_strcmp(buf, "supported_rates") == 0) { 2389214503Srpaulo if (hostapd_parse_rates(&conf->supported_rates, pos)) { 2390214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid rate " 2391214503Srpaulo "list", line); 2392214503Srpaulo errors++; 2393214503Srpaulo } 2394214503Srpaulo } else if (os_strcmp(buf, "basic_rates") == 0) { 2395214503Srpaulo if (hostapd_parse_rates(&conf->basic_rates, pos)) { 2396214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid rate " 2397214503Srpaulo "list", line); 2398214503Srpaulo errors++; 2399214503Srpaulo } 2400214503Srpaulo } else if (os_strcmp(buf, "preamble") == 0) { 2401214503Srpaulo if (atoi(pos)) 2402214503Srpaulo conf->preamble = SHORT_PREAMBLE; 2403214503Srpaulo else 2404214503Srpaulo conf->preamble = LONG_PREAMBLE; 2405214503Srpaulo } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) { 2406214503Srpaulo bss->ignore_broadcast_ssid = atoi(pos); 2407214503Srpaulo } else if (os_strcmp(buf, "wep_default_key") == 0) { 2408214503Srpaulo bss->ssid.wep.idx = atoi(pos); 2409214503Srpaulo if (bss->ssid.wep.idx > 3) { 2410214503Srpaulo wpa_printf(MSG_ERROR, "Invalid " 2411214503Srpaulo "wep_default_key index %d", 2412214503Srpaulo bss->ssid.wep.idx); 2413214503Srpaulo errors++; 2414214503Srpaulo } 2415214503Srpaulo } else if (os_strcmp(buf, "wep_key0") == 0 || 2416214503Srpaulo os_strcmp(buf, "wep_key1") == 0 || 2417214503Srpaulo os_strcmp(buf, "wep_key2") == 0 || 2418214503Srpaulo os_strcmp(buf, "wep_key3") == 0) { 2419214503Srpaulo if (hostapd_config_read_wep(&bss->ssid.wep, 2420214503Srpaulo buf[7] - '0', pos)) { 2421214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid WEP " 2422214503Srpaulo "key '%s'", line, buf); 2423214503Srpaulo errors++; 2424214503Srpaulo } 2425214503Srpaulo#ifndef CONFIG_NO_VLAN 2426214503Srpaulo } else if (os_strcmp(buf, "dynamic_vlan") == 0) { 2427214503Srpaulo bss->ssid.dynamic_vlan = atoi(pos); 2428214503Srpaulo } else if (os_strcmp(buf, "vlan_file") == 0) { 2429214503Srpaulo if (hostapd_config_read_vlan_file(bss, pos)) { 2430214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: failed to " 2431214503Srpaulo "read VLAN file '%s'", line, pos); 2432214503Srpaulo errors++; 2433214503Srpaulo } 2434252726Srpaulo } else if (os_strcmp(buf, "vlan_naming") == 0) { 2435252726Srpaulo bss->ssid.vlan_naming = atoi(pos); 2436252726Srpaulo if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END || 2437252726Srpaulo bss->ssid.vlan_naming < 0) { 2438252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2439252726Srpaulo "naming scheme %d", line, 2440252726Srpaulo bss->ssid.vlan_naming); 2441252726Srpaulo errors++; 2442252726Srpaulo } 2443214503Srpaulo#ifdef CONFIG_FULL_DYNAMIC_VLAN 2444214503Srpaulo } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) { 2445214503Srpaulo bss->ssid.vlan_tagged_interface = os_strdup(pos); 2446214503Srpaulo#endif /* CONFIG_FULL_DYNAMIC_VLAN */ 2447214503Srpaulo#endif /* CONFIG_NO_VLAN */ 2448214503Srpaulo } else if (os_strcmp(buf, "ap_table_max_size") == 0) { 2449214503Srpaulo conf->ap_table_max_size = atoi(pos); 2450214503Srpaulo } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) { 2451214503Srpaulo conf->ap_table_expiration_time = atoi(pos); 2452214503Srpaulo } else if (os_strncmp(buf, "tx_queue_", 9) == 0) { 2453214503Srpaulo if (hostapd_config_tx_queue(conf, buf, pos)) { 2454214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid TX " 2455214503Srpaulo "queue item", line); 2456214503Srpaulo errors++; 2457214503Srpaulo } 2458214503Srpaulo } else if (os_strcmp(buf, "wme_enabled") == 0 || 2459214503Srpaulo os_strcmp(buf, "wmm_enabled") == 0) { 2460214503Srpaulo bss->wmm_enabled = atoi(pos); 2461214503Srpaulo } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) { 2462214503Srpaulo bss->wmm_uapsd = atoi(pos); 2463214503Srpaulo } else if (os_strncmp(buf, "wme_ac_", 7) == 0 || 2464214503Srpaulo os_strncmp(buf, "wmm_ac_", 7) == 0) { 2465252726Srpaulo if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf, 2466252726Srpaulo pos)) { 2467214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid WMM " 2468214503Srpaulo "ac item", line); 2469214503Srpaulo errors++; 2470214503Srpaulo } 2471214503Srpaulo } else if (os_strcmp(buf, "bss") == 0) { 2472214503Srpaulo if (hostapd_config_bss(conf, pos)) { 2473214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid bss " 2474214503Srpaulo "item", line); 2475214503Srpaulo errors++; 2476214503Srpaulo } 2477214503Srpaulo } else if (os_strcmp(buf, "bssid") == 0) { 2478214503Srpaulo if (hwaddr_aton(pos, bss->bssid)) { 2479214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid bssid " 2480214503Srpaulo "item", line); 2481214503Srpaulo errors++; 2482214503Srpaulo } 2483214503Srpaulo#ifdef CONFIG_IEEE80211W 2484214503Srpaulo } else if (os_strcmp(buf, "ieee80211w") == 0) { 2485214503Srpaulo bss->ieee80211w = atoi(pos); 2486214503Srpaulo } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) { 2487214503Srpaulo bss->assoc_sa_query_max_timeout = atoi(pos); 2488214503Srpaulo if (bss->assoc_sa_query_max_timeout == 0) { 2489214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2490214503Srpaulo "assoc_sa_query_max_timeout", line); 2491214503Srpaulo errors++; 2492214503Srpaulo } 2493214503Srpaulo } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0) 2494214503Srpaulo { 2495214503Srpaulo bss->assoc_sa_query_retry_timeout = atoi(pos); 2496214503Srpaulo if (bss->assoc_sa_query_retry_timeout == 0) { 2497214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2498214503Srpaulo "assoc_sa_query_retry_timeout", 2499214503Srpaulo line); 2500214503Srpaulo errors++; 2501214503Srpaulo } 2502214503Srpaulo#endif /* CONFIG_IEEE80211W */ 2503214503Srpaulo#ifdef CONFIG_IEEE80211N 2504214503Srpaulo } else if (os_strcmp(buf, "ieee80211n") == 0) { 2505214503Srpaulo conf->ieee80211n = atoi(pos); 2506214503Srpaulo } else if (os_strcmp(buf, "ht_capab") == 0) { 2507214503Srpaulo if (hostapd_config_ht_capab(conf, pos) < 0) { 2508214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2509214503Srpaulo "ht_capab", line); 2510214503Srpaulo errors++; 2511214503Srpaulo } 2512252726Srpaulo } else if (os_strcmp(buf, "require_ht") == 0) { 2513252726Srpaulo conf->require_ht = atoi(pos); 2514214503Srpaulo#endif /* CONFIG_IEEE80211N */ 2515252726Srpaulo#ifdef CONFIG_IEEE80211AC 2516252726Srpaulo } else if (os_strcmp(buf, "ieee80211ac") == 0) { 2517252726Srpaulo conf->ieee80211ac = atoi(pos); 2518252726Srpaulo } else if (os_strcmp(buf, "vht_capab") == 0) { 2519252726Srpaulo if (hostapd_config_vht_capab(conf, pos) < 0) { 2520252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2521252726Srpaulo "vht_capab", line); 2522252726Srpaulo errors++; 2523252726Srpaulo } 2524252726Srpaulo } else if (os_strcmp(buf, "require_vht") == 0) { 2525252726Srpaulo conf->require_vht = atoi(pos); 2526252726Srpaulo } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) { 2527252726Srpaulo conf->vht_oper_chwidth = atoi(pos); 2528252726Srpaulo } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0) 2529252726Srpaulo { 2530252726Srpaulo conf->vht_oper_centr_freq_seg0_idx = atoi(pos); 2531252726Srpaulo } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) 2532252726Srpaulo { 2533252726Srpaulo conf->vht_oper_centr_freq_seg1_idx = atoi(pos); 2534252726Srpaulo#endif /* CONFIG_IEEE80211AC */ 2535214503Srpaulo } else if (os_strcmp(buf, "max_listen_interval") == 0) { 2536214503Srpaulo bss->max_listen_interval = atoi(pos); 2537252726Srpaulo } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) { 2538252726Srpaulo bss->disable_pmksa_caching = atoi(pos); 2539214503Srpaulo } else if (os_strcmp(buf, "okc") == 0) { 2540214503Srpaulo bss->okc = atoi(pos); 2541214503Srpaulo#ifdef CONFIG_WPS 2542214503Srpaulo } else if (os_strcmp(buf, "wps_state") == 0) { 2543214503Srpaulo bss->wps_state = atoi(pos); 2544214503Srpaulo if (bss->wps_state < 0 || bss->wps_state > 2) { 2545214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2546214503Srpaulo "wps_state", line); 2547214503Srpaulo errors++; 2548214503Srpaulo } 2549214503Srpaulo } else if (os_strcmp(buf, "ap_setup_locked") == 0) { 2550214503Srpaulo bss->ap_setup_locked = atoi(pos); 2551214503Srpaulo } else if (os_strcmp(buf, "uuid") == 0) { 2552214503Srpaulo if (uuid_str2bin(pos, bss->uuid)) { 2553214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid UUID", 2554214503Srpaulo line); 2555214503Srpaulo errors++; 2556214503Srpaulo } 2557214503Srpaulo } else if (os_strcmp(buf, "wps_pin_requests") == 0) { 2558214503Srpaulo os_free(bss->wps_pin_requests); 2559214503Srpaulo bss->wps_pin_requests = os_strdup(pos); 2560214503Srpaulo } else if (os_strcmp(buf, "device_name") == 0) { 2561214503Srpaulo if (os_strlen(pos) > 32) { 2562214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Too long " 2563214503Srpaulo "device_name", line); 2564214503Srpaulo errors++; 2565214503Srpaulo } 2566214503Srpaulo os_free(bss->device_name); 2567214503Srpaulo bss->device_name = os_strdup(pos); 2568214503Srpaulo } else if (os_strcmp(buf, "manufacturer") == 0) { 2569214503Srpaulo if (os_strlen(pos) > 64) { 2570214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Too long " 2571214503Srpaulo "manufacturer", line); 2572214503Srpaulo errors++; 2573214503Srpaulo } 2574214503Srpaulo os_free(bss->manufacturer); 2575214503Srpaulo bss->manufacturer = os_strdup(pos); 2576214503Srpaulo } else if (os_strcmp(buf, "model_name") == 0) { 2577214503Srpaulo if (os_strlen(pos) > 32) { 2578214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Too long " 2579214503Srpaulo "model_name", line); 2580214503Srpaulo errors++; 2581214503Srpaulo } 2582214503Srpaulo os_free(bss->model_name); 2583214503Srpaulo bss->model_name = os_strdup(pos); 2584214503Srpaulo } else if (os_strcmp(buf, "model_number") == 0) { 2585214503Srpaulo if (os_strlen(pos) > 32) { 2586214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Too long " 2587214503Srpaulo "model_number", line); 2588214503Srpaulo errors++; 2589214503Srpaulo } 2590214503Srpaulo os_free(bss->model_number); 2591214503Srpaulo bss->model_number = os_strdup(pos); 2592214503Srpaulo } else if (os_strcmp(buf, "serial_number") == 0) { 2593214503Srpaulo if (os_strlen(pos) > 32) { 2594214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: Too long " 2595214503Srpaulo "serial_number", line); 2596214503Srpaulo errors++; 2597214503Srpaulo } 2598214503Srpaulo os_free(bss->serial_number); 2599214503Srpaulo bss->serial_number = os_strdup(pos); 2600214503Srpaulo } else if (os_strcmp(buf, "device_type") == 0) { 2601252726Srpaulo if (wps_dev_type_str2bin(pos, bss->device_type)) 2602252726Srpaulo errors++; 2603214503Srpaulo } else if (os_strcmp(buf, "config_methods") == 0) { 2604214503Srpaulo os_free(bss->config_methods); 2605214503Srpaulo bss->config_methods = os_strdup(pos); 2606214503Srpaulo } else if (os_strcmp(buf, "os_version") == 0) { 2607214503Srpaulo if (hexstr2bin(pos, bss->os_version, 4)) { 2608214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2609214503Srpaulo "os_version", line); 2610214503Srpaulo errors++; 2611214503Srpaulo } 2612214503Srpaulo } else if (os_strcmp(buf, "ap_pin") == 0) { 2613214503Srpaulo os_free(bss->ap_pin); 2614214503Srpaulo bss->ap_pin = os_strdup(pos); 2615214503Srpaulo } else if (os_strcmp(buf, "skip_cred_build") == 0) { 2616214503Srpaulo bss->skip_cred_build = atoi(pos); 2617214503Srpaulo } else if (os_strcmp(buf, "extra_cred") == 0) { 2618214503Srpaulo os_free(bss->extra_cred); 2619214503Srpaulo bss->extra_cred = 2620214503Srpaulo (u8 *) os_readfile(pos, &bss->extra_cred_len); 2621214503Srpaulo if (bss->extra_cred == NULL) { 2622214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: could not " 2623214503Srpaulo "read Credentials from '%s'", 2624214503Srpaulo line, pos); 2625214503Srpaulo errors++; 2626214503Srpaulo } 2627214503Srpaulo } else if (os_strcmp(buf, "wps_cred_processing") == 0) { 2628214503Srpaulo bss->wps_cred_processing = atoi(pos); 2629214503Srpaulo } else if (os_strcmp(buf, "ap_settings") == 0) { 2630214503Srpaulo os_free(bss->ap_settings); 2631214503Srpaulo bss->ap_settings = 2632214503Srpaulo (u8 *) os_readfile(pos, &bss->ap_settings_len); 2633214503Srpaulo if (bss->ap_settings == NULL) { 2634214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: could not " 2635214503Srpaulo "read AP Settings from '%s'", 2636214503Srpaulo line, pos); 2637214503Srpaulo errors++; 2638214503Srpaulo } 2639214503Srpaulo } else if (os_strcmp(buf, "upnp_iface") == 0) { 2640214503Srpaulo bss->upnp_iface = os_strdup(pos); 2641214503Srpaulo } else if (os_strcmp(buf, "friendly_name") == 0) { 2642214503Srpaulo os_free(bss->friendly_name); 2643214503Srpaulo bss->friendly_name = os_strdup(pos); 2644214503Srpaulo } else if (os_strcmp(buf, "manufacturer_url") == 0) { 2645214503Srpaulo os_free(bss->manufacturer_url); 2646214503Srpaulo bss->manufacturer_url = os_strdup(pos); 2647214503Srpaulo } else if (os_strcmp(buf, "model_description") == 0) { 2648214503Srpaulo os_free(bss->model_description); 2649214503Srpaulo bss->model_description = os_strdup(pos); 2650214503Srpaulo } else if (os_strcmp(buf, "model_url") == 0) { 2651214503Srpaulo os_free(bss->model_url); 2652214503Srpaulo bss->model_url = os_strdup(pos); 2653214503Srpaulo } else if (os_strcmp(buf, "upc") == 0) { 2654214503Srpaulo os_free(bss->upc); 2655214503Srpaulo bss->upc = os_strdup(pos); 2656252726Srpaulo } else if (os_strcmp(buf, "pbc_in_m1") == 0) { 2657252726Srpaulo bss->pbc_in_m1 = atoi(pos); 2658252726Srpaulo#ifdef CONFIG_WPS_NFC 2659252726Srpaulo } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) { 2660252726Srpaulo bss->wps_nfc_dev_pw_id = atoi(pos); 2661252726Srpaulo if (bss->wps_nfc_dev_pw_id < 0x10 || 2662252726Srpaulo bss->wps_nfc_dev_pw_id > 0xffff) { 2663252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 2664252726Srpaulo "wps_nfc_dev_pw_id value", line); 2665252726Srpaulo errors++; 2666252726Srpaulo } 2667252726Srpaulo } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) { 2668252726Srpaulo wpabuf_free(bss->wps_nfc_dh_pubkey); 2669252726Srpaulo bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos); 2670252726Srpaulo } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) { 2671252726Srpaulo wpabuf_free(bss->wps_nfc_dh_privkey); 2672252726Srpaulo bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos); 2673252726Srpaulo } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) { 2674252726Srpaulo wpabuf_free(bss->wps_nfc_dev_pw); 2675252726Srpaulo bss->wps_nfc_dev_pw = hostapd_parse_bin(pos); 2676252726Srpaulo#endif /* CONFIG_WPS_NFC */ 2677214503Srpaulo#endif /* CONFIG_WPS */ 2678252726Srpaulo#ifdef CONFIG_P2P_MANAGER 2679252726Srpaulo } else if (os_strcmp(buf, "manage_p2p") == 0) { 2680252726Srpaulo int manage = atoi(pos); 2681252726Srpaulo if (manage) 2682252726Srpaulo bss->p2p |= P2P_MANAGE; 2683252726Srpaulo else 2684252726Srpaulo bss->p2p &= ~P2P_MANAGE; 2685252726Srpaulo } else if (os_strcmp(buf, "allow_cross_connection") == 0) { 2686252726Srpaulo if (atoi(pos)) 2687252726Srpaulo bss->p2p |= P2P_ALLOW_CROSS_CONNECTION; 2688252726Srpaulo else 2689252726Srpaulo bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION; 2690252726Srpaulo#endif /* CONFIG_P2P_MANAGER */ 2691252726Srpaulo } else if (os_strcmp(buf, "disassoc_low_ack") == 0) { 2692252726Srpaulo bss->disassoc_low_ack = atoi(pos); 2693252726Srpaulo } else if (os_strcmp(buf, "tdls_prohibit") == 0) { 2694252726Srpaulo int val = atoi(pos); 2695252726Srpaulo if (val) 2696252726Srpaulo bss->tdls |= TDLS_PROHIBIT; 2697252726Srpaulo else 2698252726Srpaulo bss->tdls &= ~TDLS_PROHIBIT; 2699252726Srpaulo } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) { 2700252726Srpaulo int val = atoi(pos); 2701252726Srpaulo if (val) 2702252726Srpaulo bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH; 2703252726Srpaulo else 2704252726Srpaulo bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH; 2705252726Srpaulo#ifdef CONFIG_RSN_TESTING 2706252726Srpaulo } else if (os_strcmp(buf, "rsn_testing") == 0) { 2707252726Srpaulo extern int rsn_testing; 2708252726Srpaulo rsn_testing = atoi(pos); 2709252726Srpaulo#endif /* CONFIG_RSN_TESTING */ 2710252726Srpaulo } else if (os_strcmp(buf, "time_advertisement") == 0) { 2711252726Srpaulo bss->time_advertisement = atoi(pos); 2712252726Srpaulo } else if (os_strcmp(buf, "time_zone") == 0) { 2713252726Srpaulo size_t tz_len = os_strlen(pos); 2714252726Srpaulo if (tz_len < 4 || tz_len > 255) { 2715252726Srpaulo wpa_printf(MSG_DEBUG, "Line %d: invalid " 2716252726Srpaulo "time_zone", line); 2717252726Srpaulo errors++; 2718252726Srpaulo return errors; 2719252726Srpaulo } 2720252726Srpaulo os_free(bss->time_zone); 2721252726Srpaulo bss->time_zone = os_strdup(pos); 2722252726Srpaulo if (bss->time_zone == NULL) 2723252726Srpaulo errors++; 2724252726Srpaulo#ifdef CONFIG_WNM 2725252726Srpaulo } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) { 2726252726Srpaulo bss->wnm_sleep_mode = atoi(pos); 2727252726Srpaulo } else if (os_strcmp(buf, "bss_transition") == 0) { 2728252726Srpaulo bss->bss_transition = atoi(pos); 2729252726Srpaulo#endif /* CONFIG_WNM */ 2730252726Srpaulo#ifdef CONFIG_INTERWORKING 2731252726Srpaulo } else if (os_strcmp(buf, "interworking") == 0) { 2732252726Srpaulo bss->interworking = atoi(pos); 2733252726Srpaulo } else if (os_strcmp(buf, "access_network_type") == 0) { 2734252726Srpaulo bss->access_network_type = atoi(pos); 2735252726Srpaulo if (bss->access_network_type < 0 || 2736252726Srpaulo bss->access_network_type > 15) { 2737252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2738252726Srpaulo "access_network_type", line); 2739252726Srpaulo errors++; 2740252726Srpaulo } 2741252726Srpaulo } else if (os_strcmp(buf, "internet") == 0) { 2742252726Srpaulo bss->internet = atoi(pos); 2743252726Srpaulo } else if (os_strcmp(buf, "asra") == 0) { 2744252726Srpaulo bss->asra = atoi(pos); 2745252726Srpaulo } else if (os_strcmp(buf, "esr") == 0) { 2746252726Srpaulo bss->esr = atoi(pos); 2747252726Srpaulo } else if (os_strcmp(buf, "uesa") == 0) { 2748252726Srpaulo bss->uesa = atoi(pos); 2749252726Srpaulo } else if (os_strcmp(buf, "venue_group") == 0) { 2750252726Srpaulo bss->venue_group = atoi(pos); 2751252726Srpaulo bss->venue_info_set = 1; 2752252726Srpaulo } else if (os_strcmp(buf, "venue_type") == 0) { 2753252726Srpaulo bss->venue_type = atoi(pos); 2754252726Srpaulo bss->venue_info_set = 1; 2755252726Srpaulo } else if (os_strcmp(buf, "hessid") == 0) { 2756252726Srpaulo if (hwaddr_aton(pos, bss->hessid)) { 2757252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid " 2758252726Srpaulo "hessid", line); 2759252726Srpaulo errors++; 2760252726Srpaulo } 2761252726Srpaulo } else if (os_strcmp(buf, "roaming_consortium") == 0) { 2762252726Srpaulo if (parse_roaming_consortium(bss, pos, line) < 0) 2763252726Srpaulo errors++; 2764252726Srpaulo } else if (os_strcmp(buf, "venue_name") == 0) { 2765252726Srpaulo if (parse_venue_name(bss, pos, line) < 0) 2766252726Srpaulo errors++; 2767252726Srpaulo } else if (os_strcmp(buf, "network_auth_type") == 0) { 2768252726Srpaulo u8 auth_type; 2769252726Srpaulo u16 redirect_url_len; 2770252726Srpaulo if (hexstr2bin(pos, &auth_type, 1)) { 2771252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 2772252726Srpaulo "network_auth_type '%s'", 2773252726Srpaulo line, pos); 2774252726Srpaulo errors++; 2775252726Srpaulo return errors; 2776252726Srpaulo } 2777252726Srpaulo if (auth_type == 0 || auth_type == 2) 2778252726Srpaulo redirect_url_len = os_strlen(pos + 2); 2779252726Srpaulo else 2780252726Srpaulo redirect_url_len = 0; 2781252726Srpaulo os_free(bss->network_auth_type); 2782252726Srpaulo bss->network_auth_type = 2783252726Srpaulo os_malloc(redirect_url_len + 3 + 1); 2784252726Srpaulo if (bss->network_auth_type == NULL) { 2785252726Srpaulo errors++; 2786252726Srpaulo return errors; 2787252726Srpaulo } 2788252726Srpaulo *bss->network_auth_type = auth_type; 2789252726Srpaulo WPA_PUT_LE16(bss->network_auth_type + 1, 2790252726Srpaulo redirect_url_len); 2791252726Srpaulo if (redirect_url_len) 2792252726Srpaulo os_memcpy(bss->network_auth_type + 3, 2793252726Srpaulo pos + 2, redirect_url_len); 2794252726Srpaulo bss->network_auth_type_len = 3 + redirect_url_len; 2795252726Srpaulo } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) { 2796252726Srpaulo if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1)) 2797252726Srpaulo { 2798252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 2799252726Srpaulo "ipaddr_type_availability '%s'", 2800252726Srpaulo line, pos); 2801252726Srpaulo bss->ipaddr_type_configured = 0; 2802252726Srpaulo errors++; 2803252726Srpaulo return errors; 2804252726Srpaulo } 2805252726Srpaulo bss->ipaddr_type_configured = 1; 2806252726Srpaulo } else if (os_strcmp(buf, "domain_name") == 0) { 2807252726Srpaulo int j, num_domains, domain_len, domain_list_len = 0; 2808252726Srpaulo char *tok_start, *tok_prev; 2809252726Srpaulo u8 *domain_list, *domain_ptr; 2810252726Srpaulo 2811252726Srpaulo domain_list_len = os_strlen(pos) + 1; 2812252726Srpaulo domain_list = os_malloc(domain_list_len); 2813252726Srpaulo if (domain_list == NULL) { 2814252726Srpaulo errors++; 2815252726Srpaulo return errors; 2816252726Srpaulo } 2817252726Srpaulo 2818252726Srpaulo domain_ptr = domain_list; 2819252726Srpaulo tok_prev = pos; 2820252726Srpaulo num_domains = 1; 2821252726Srpaulo while ((tok_prev = os_strchr(tok_prev, ','))) { 2822252726Srpaulo num_domains++; 2823252726Srpaulo tok_prev++; 2824252726Srpaulo } 2825252726Srpaulo tok_prev = pos; 2826252726Srpaulo for (j = 0; j < num_domains; j++) { 2827252726Srpaulo tok_start = os_strchr(tok_prev, ','); 2828252726Srpaulo if (tok_start) { 2829252726Srpaulo domain_len = tok_start - tok_prev; 2830252726Srpaulo *domain_ptr = domain_len; 2831252726Srpaulo os_memcpy(domain_ptr + 1, tok_prev, 2832252726Srpaulo domain_len); 2833252726Srpaulo domain_ptr += domain_len + 1; 2834252726Srpaulo tok_prev = ++tok_start; 2835252726Srpaulo } else { 2836252726Srpaulo domain_len = os_strlen(tok_prev); 2837252726Srpaulo *domain_ptr = domain_len; 2838252726Srpaulo os_memcpy(domain_ptr + 1, tok_prev, 2839252726Srpaulo domain_len); 2840252726Srpaulo domain_ptr += domain_len + 1; 2841252726Srpaulo } 2842252726Srpaulo } 2843252726Srpaulo 2844252726Srpaulo os_free(bss->domain_name); 2845252726Srpaulo bss->domain_name = domain_list; 2846252726Srpaulo bss->domain_name_len = domain_list_len; 2847252726Srpaulo } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) { 2848252726Srpaulo if (parse_3gpp_cell_net(bss, pos, line) < 0) 2849252726Srpaulo errors++; 2850252726Srpaulo } else if (os_strcmp(buf, "nai_realm") == 0) { 2851252726Srpaulo if (parse_nai_realm(bss, pos, line) < 0) 2852252726Srpaulo errors++; 2853252726Srpaulo } else if (os_strcmp(buf, "gas_frag_limit") == 0) { 2854252726Srpaulo bss->gas_frag_limit = atoi(pos); 2855252726Srpaulo } else if (os_strcmp(buf, "gas_comeback_delay") == 0) { 2856252726Srpaulo bss->gas_comeback_delay = atoi(pos); 2857252726Srpaulo#endif /* CONFIG_INTERWORKING */ 2858252726Srpaulo#ifdef CONFIG_RADIUS_TEST 2859252726Srpaulo } else if (os_strcmp(buf, "dump_msk_file") == 0) { 2860252726Srpaulo os_free(bss->dump_msk_file); 2861252726Srpaulo bss->dump_msk_file = os_strdup(pos); 2862252726Srpaulo#endif /* CONFIG_RADIUS_TEST */ 2863252726Srpaulo#ifdef CONFIG_HS20 2864252726Srpaulo } else if (os_strcmp(buf, "hs20") == 0) { 2865252726Srpaulo bss->hs20 = atoi(pos); 2866252726Srpaulo } else if (os_strcmp(buf, "disable_dgaf") == 0) { 2867252726Srpaulo bss->disable_dgaf = atoi(pos); 2868252726Srpaulo } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) { 2869252726Srpaulo if (hs20_parse_oper_friendly_name(bss, pos, line) < 0) 2870252726Srpaulo errors++; 2871252726Srpaulo } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) { 2872252726Srpaulo if (hs20_parse_wan_metrics(bss, pos, line) < 0) { 2873252726Srpaulo errors++; 2874252726Srpaulo return errors; 2875252726Srpaulo } 2876252726Srpaulo } else if (os_strcmp(buf, "hs20_conn_capab") == 0) { 2877252726Srpaulo if (hs20_parse_conn_capab(bss, pos, line) < 0) { 2878252726Srpaulo errors++; 2879252726Srpaulo return errors; 2880252726Srpaulo } 2881252726Srpaulo } else if (os_strcmp(buf, "hs20_operating_class") == 0) { 2882252726Srpaulo u8 *oper_class; 2883252726Srpaulo size_t oper_class_len; 2884252726Srpaulo oper_class_len = os_strlen(pos); 2885252726Srpaulo if (oper_class_len < 2 || (oper_class_len & 0x01)) { 2886252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 2887252726Srpaulo "hs20_operating_class '%s'", 2888252726Srpaulo line, pos); 2889252726Srpaulo errors++; 2890252726Srpaulo return errors; 2891252726Srpaulo } 2892252726Srpaulo oper_class_len /= 2; 2893252726Srpaulo oper_class = os_malloc(oper_class_len); 2894252726Srpaulo if (oper_class == NULL) { 2895252726Srpaulo errors++; 2896252726Srpaulo return errors; 2897252726Srpaulo } 2898252726Srpaulo if (hexstr2bin(pos, oper_class, oper_class_len)) { 2899252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 2900252726Srpaulo "hs20_operating_class '%s'", 2901252726Srpaulo line, pos); 2902252726Srpaulo os_free(oper_class); 2903252726Srpaulo errors++; 2904252726Srpaulo return errors; 2905252726Srpaulo } 2906252726Srpaulo os_free(bss->hs20_operating_class); 2907252726Srpaulo bss->hs20_operating_class = oper_class; 2908252726Srpaulo bss->hs20_operating_class_len = oper_class_len; 2909252726Srpaulo#endif /* CONFIG_HS20 */ 2910252726Srpaulo } else if (os_strcmp(buf, "vendor_elements") == 0) { 2911252726Srpaulo struct wpabuf *elems; 2912252726Srpaulo size_t len = os_strlen(pos); 2913252726Srpaulo if (len & 0x01) { 2914252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 2915252726Srpaulo "vendor_elements '%s'", line, pos); 2916252726Srpaulo return 1; 2917252726Srpaulo } 2918252726Srpaulo len /= 2; 2919252726Srpaulo if (len == 0) { 2920252726Srpaulo wpabuf_free(bss->vendor_elements); 2921252726Srpaulo bss->vendor_elements = NULL; 2922252726Srpaulo return 0; 2923252726Srpaulo } 2924252726Srpaulo 2925252726Srpaulo elems = wpabuf_alloc(len); 2926252726Srpaulo if (elems == NULL) 2927252726Srpaulo return 1; 2928252726Srpaulo 2929252726Srpaulo if (hexstr2bin(pos, wpabuf_put(elems, len), len)) { 2930252726Srpaulo wpabuf_free(elems); 2931252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: Invalid " 2932252726Srpaulo "vendor_elements '%s'", line, pos); 2933252726Srpaulo return 1; 2934252726Srpaulo } 2935252726Srpaulo 2936252726Srpaulo wpabuf_free(bss->vendor_elements); 2937252726Srpaulo bss->vendor_elements = elems; 2938214503Srpaulo } else { 2939214503Srpaulo wpa_printf(MSG_ERROR, "Line %d: unknown configuration " 2940214503Srpaulo "item '%s'", line, buf); 2941214503Srpaulo errors++; 2942214503Srpaulo } 2943214503Srpaulo } 2944214503Srpaulo 2945252726Srpaulo return errors; 2946252726Srpaulo} 2947214503Srpaulo 2948214503Srpaulo 2949252726Srpaulostatic void hostapd_set_security_params(struct hostapd_bss_config *bss) 2950252726Srpaulo{ 2951252726Srpaulo int pairwise; 2952252726Srpaulo 2953252726Srpaulo if (bss->individual_wep_key_len == 0) { 2954252726Srpaulo /* individual keys are not use; can use key idx0 for 2955252726Srpaulo * broadcast keys */ 2956252726Srpaulo bss->broadcast_key_idx_min = 0; 2957252726Srpaulo } 2958252726Srpaulo 2959252726Srpaulo /* Select group cipher based on the enabled pairwise cipher 2960252726Srpaulo * suites */ 2961252726Srpaulo pairwise = 0; 2962252726Srpaulo if (bss->wpa & 1) 2963252726Srpaulo pairwise |= bss->wpa_pairwise; 2964252726Srpaulo if (bss->wpa & 2) { 2965252726Srpaulo if (bss->rsn_pairwise == 0) 2966252726Srpaulo bss->rsn_pairwise = bss->wpa_pairwise; 2967252726Srpaulo pairwise |= bss->rsn_pairwise; 2968252726Srpaulo } 2969252726Srpaulo if (pairwise & WPA_CIPHER_TKIP) 2970252726Srpaulo bss->wpa_group = WPA_CIPHER_TKIP; 2971252726Srpaulo else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == 2972252726Srpaulo WPA_CIPHER_GCMP) 2973252726Srpaulo bss->wpa_group = WPA_CIPHER_GCMP; 2974252726Srpaulo else 2975252726Srpaulo bss->wpa_group = WPA_CIPHER_CCMP; 2976252726Srpaulo 2977252726Srpaulo bss->radius->auth_server = bss->radius->auth_servers; 2978252726Srpaulo bss->radius->acct_server = bss->radius->acct_servers; 2979252726Srpaulo 2980252726Srpaulo if (bss->wpa && bss->ieee802_1x) { 2981252726Srpaulo bss->ssid.security_policy = SECURITY_WPA; 2982252726Srpaulo } else if (bss->wpa) { 2983252726Srpaulo bss->ssid.security_policy = SECURITY_WPA_PSK; 2984252726Srpaulo } else if (bss->ieee802_1x) { 2985252726Srpaulo int cipher = WPA_CIPHER_NONE; 2986252726Srpaulo bss->ssid.security_policy = SECURITY_IEEE_802_1X; 2987252726Srpaulo bss->ssid.wep.default_len = bss->default_wep_key_len; 2988252726Srpaulo if (bss->default_wep_key_len) 2989252726Srpaulo cipher = bss->default_wep_key_len >= 13 ? 2990252726Srpaulo WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40; 2991252726Srpaulo bss->wpa_group = cipher; 2992252726Srpaulo bss->wpa_pairwise = cipher; 2993252726Srpaulo bss->rsn_pairwise = cipher; 2994252726Srpaulo } else if (bss->ssid.wep.keys_set) { 2995252726Srpaulo int cipher = WPA_CIPHER_WEP40; 2996252726Srpaulo if (bss->ssid.wep.len[0] >= 13) 2997252726Srpaulo cipher = WPA_CIPHER_WEP104; 2998252726Srpaulo bss->ssid.security_policy = SECURITY_STATIC_WEP; 2999252726Srpaulo bss->wpa_group = cipher; 3000252726Srpaulo bss->wpa_pairwise = cipher; 3001252726Srpaulo bss->rsn_pairwise = cipher; 3002252726Srpaulo } else { 3003252726Srpaulo bss->ssid.security_policy = SECURITY_PLAINTEXT; 3004252726Srpaulo bss->wpa_group = WPA_CIPHER_NONE; 3005252726Srpaulo bss->wpa_pairwise = WPA_CIPHER_NONE; 3006252726Srpaulo bss->rsn_pairwise = WPA_CIPHER_NONE; 3007252726Srpaulo } 3008252726Srpaulo} 3009252726Srpaulo 3010252726Srpaulo 3011252726Srpaulo/** 3012252726Srpaulo * hostapd_config_read - Read and parse a configuration file 3013252726Srpaulo * @fname: Configuration file name (including path, if needed) 3014252726Srpaulo * Returns: Allocated configuration data structure 3015252726Srpaulo */ 3016252726Srpaulostruct hostapd_config * hostapd_config_read(const char *fname) 3017252726Srpaulo{ 3018252726Srpaulo struct hostapd_config *conf; 3019252726Srpaulo struct hostapd_bss_config *bss; 3020252726Srpaulo FILE *f; 3021252726Srpaulo char buf[512], *pos; 3022252726Srpaulo int line = 0; 3023252726Srpaulo int errors = 0; 3024252726Srpaulo size_t i; 3025252726Srpaulo 3026252726Srpaulo f = fopen(fname, "r"); 3027252726Srpaulo if (f == NULL) { 3028252726Srpaulo wpa_printf(MSG_ERROR, "Could not open configuration file '%s' " 3029252726Srpaulo "for reading.", fname); 3030252726Srpaulo return NULL; 3031252726Srpaulo } 3032252726Srpaulo 3033252726Srpaulo conf = hostapd_config_defaults(); 3034252726Srpaulo if (conf == NULL) { 3035252726Srpaulo fclose(f); 3036252726Srpaulo return NULL; 3037252726Srpaulo } 3038252726Srpaulo 3039252726Srpaulo /* set default driver based on configuration */ 3040252726Srpaulo conf->driver = wpa_drivers[0]; 3041252726Srpaulo if (conf->driver == NULL) { 3042252726Srpaulo wpa_printf(MSG_ERROR, "No driver wrappers registered!"); 3043252726Srpaulo hostapd_config_free(conf); 3044252726Srpaulo fclose(f); 3045252726Srpaulo return NULL; 3046252726Srpaulo } 3047252726Srpaulo 3048252726Srpaulo bss = conf->last_bss = conf->bss; 3049252726Srpaulo 3050252726Srpaulo while (fgets(buf, sizeof(buf), f)) { 3051252726Srpaulo bss = conf->last_bss; 3052252726Srpaulo line++; 3053252726Srpaulo 3054252726Srpaulo if (buf[0] == '#') 3055252726Srpaulo continue; 3056252726Srpaulo pos = buf; 3057252726Srpaulo while (*pos != '\0') { 3058252726Srpaulo if (*pos == '\n') { 3059252726Srpaulo *pos = '\0'; 3060252726Srpaulo break; 3061252726Srpaulo } 3062252726Srpaulo pos++; 3063214503Srpaulo } 3064252726Srpaulo if (buf[0] == '\0') 3065252726Srpaulo continue; 3066214503Srpaulo 3067252726Srpaulo pos = os_strchr(buf, '='); 3068252726Srpaulo if (pos == NULL) { 3069252726Srpaulo wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'", 3070252726Srpaulo line, buf); 3071252726Srpaulo errors++; 3072252726Srpaulo continue; 3073214503Srpaulo } 3074252726Srpaulo *pos = '\0'; 3075252726Srpaulo pos++; 3076252726Srpaulo errors += hostapd_config_fill(conf, bss, buf, pos, line); 3077252726Srpaulo } 3078214503Srpaulo 3079252726Srpaulo fclose(f); 3080214503Srpaulo 3081252726Srpaulo for (i = 0; i < conf->num_bss; i++) 3082252726Srpaulo hostapd_set_security_params(&conf->bss[i]); 3083214503Srpaulo 3084214503Srpaulo if (hostapd_config_check(conf)) 3085214503Srpaulo errors++; 3086214503Srpaulo 3087252726Srpaulo#ifndef WPA_IGNORE_CONFIG_ERRORS 3088214503Srpaulo if (errors) { 3089214503Srpaulo wpa_printf(MSG_ERROR, "%d errors found in configuration file " 3090214503Srpaulo "'%s'", errors, fname); 3091214503Srpaulo hostapd_config_free(conf); 3092214503Srpaulo conf = NULL; 3093214503Srpaulo } 3094252726Srpaulo#endif /* WPA_IGNORE_CONFIG_ERRORS */ 3095214503Srpaulo 3096214503Srpaulo return conf; 3097214503Srpaulo} 3098252726Srpaulo 3099252726Srpaulo 3100252726Srpauloint hostapd_set_iface(struct hostapd_config *conf, 3101252726Srpaulo struct hostapd_bss_config *bss, char *field, char *value) 3102252726Srpaulo{ 3103252726Srpaulo int errors; 3104252726Srpaulo size_t i; 3105252726Srpaulo 3106252726Srpaulo errors = hostapd_config_fill(conf, bss, field, value, 0); 3107252726Srpaulo if (errors) { 3108252726Srpaulo wpa_printf(MSG_INFO, "Failed to set configuration field '%s' " 3109252726Srpaulo "to value '%s'", field, value); 3110252726Srpaulo return -1; 3111252726Srpaulo } 3112252726Srpaulo 3113252726Srpaulo for (i = 0; i < conf->num_bss; i++) 3114252726Srpaulo hostapd_set_security_params(&conf->bss[i]); 3115252726Srpaulo 3116252726Srpaulo if (hostapd_config_check(conf)) { 3117252726Srpaulo wpa_printf(MSG_ERROR, "Configuration check failed"); 3118252726Srpaulo return -1; 3119252726Srpaulo } 3120252726Srpaulo 3121252726Srpaulo return 0; 3122252726Srpaulo} 3123