WPS: Clean up Primary Device Type handling
Use shared functions for converting Primary Device Type between binary and string formats. In addition, use array of eight octets instead of a specific structure with multiple fields to reduce code complexity.
This commit is contained in:
parent
8e2c104fa1
commit
96750ea5e5
8 changed files with 84 additions and 95 deletions
|
@ -137,15 +137,17 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
|
||||||
struct hostapd_data *hapd = ctx;
|
struct hostapd_data *hapd = ctx;
|
||||||
char uuid[40], txt[400];
|
char uuid[40], txt[400];
|
||||||
int len;
|
int len;
|
||||||
|
char devtype[WPS_DEV_TYPE_BUFSIZE];
|
||||||
if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
|
if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
|
||||||
return;
|
return;
|
||||||
wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
|
wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
|
||||||
len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
|
len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
|
||||||
"%s " MACSTR " [%s|%s|%s|%s|%s|%d-%08X-%d]",
|
"%s " MACSTR " [%s|%s|%s|%s|%s|%s]",
|
||||||
uuid, MAC2STR(dev->mac_addr), dev->device_name,
|
uuid, MAC2STR(dev->mac_addr), dev->device_name,
|
||||||
dev->manufacturer, dev->model_name,
|
dev->manufacturer, dev->model_name,
|
||||||
dev->model_number, dev->serial_number,
|
dev->model_number, dev->serial_number,
|
||||||
dev->categ, dev->oui, dev->sub_categ);
|
wps_dev_type_bin2str(dev->pri_dev_type, devtype,
|
||||||
|
sizeof(devtype)));
|
||||||
if (len > 0 && len < (int) sizeof(txt))
|
if (len > 0 && len < (int) sizeof(txt))
|
||||||
wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
|
wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
|
||||||
|
|
||||||
|
@ -157,11 +159,12 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
|
||||||
return;
|
return;
|
||||||
os_get_time(&t);
|
os_get_time(&t);
|
||||||
fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
|
fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
|
||||||
"\t%d-%08X-%d\n",
|
"\t%s\n",
|
||||||
t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
|
t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
|
||||||
dev->manufacturer, dev->model_name, dev->model_number,
|
dev->manufacturer, dev->model_name, dev->model_number,
|
||||||
dev->serial_number,
|
dev->serial_number,
|
||||||
dev->categ, dev->oui, dev->sub_categ);
|
wps_dev_type_bin2str(dev->pri_dev_type, devtype,
|
||||||
|
sizeof(devtype)));
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -537,32 +540,12 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||||
if (os_strstr(m, "keypad"))
|
if (os_strstr(m, "keypad"))
|
||||||
wps->config_methods |= WPS_CONFIG_KEYPAD;
|
wps->config_methods |= WPS_CONFIG_KEYPAD;
|
||||||
}
|
}
|
||||||
if (hapd->conf->device_type) {
|
if (hapd->conf->device_type &&
|
||||||
char *pos;
|
wps_dev_type_str2bin(hapd->conf->device_type,
|
||||||
u8 oui[4];
|
wps->dev.pri_dev_type) < 0) {
|
||||||
/* <categ>-<OUI>-<subcateg> */
|
wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
|
||||||
wps->dev.categ = atoi(hapd->conf->device_type);
|
os_free(wps);
|
||||||
pos = os_strchr(hapd->conf->device_type, '-');
|
return -1;
|
||||||
if (pos == NULL) {
|
|
||||||
wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
|
|
||||||
os_free(wps);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
if (hexstr2bin(pos, oui, 4)) {
|
|
||||||
wpa_printf(MSG_ERROR, "WPS: Invalid device_type OUI");
|
|
||||||
os_free(wps);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
wps->dev.oui = WPA_GET_BE32(oui);
|
|
||||||
pos = os_strchr(pos, '-');
|
|
||||||
if (pos == NULL) {
|
|
||||||
wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
|
|
||||||
os_free(wps);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
wps->dev.sub_categ = atoi(pos);
|
|
||||||
}
|
}
|
||||||
wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
|
wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
|
||||||
wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
|
wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
|
||||||
|
|
|
@ -61,6 +61,9 @@ struct wps_credential {
|
||||||
size_t cred_attr_len;
|
size_t cred_attr_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define WPS_DEV_TYPE_LEN 8
|
||||||
|
#define WPS_DEV_TYPE_BUFSIZE 21
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct wps_device_data - WPS Device Data
|
* struct wps_device_data - WPS Device Data
|
||||||
* @mac_addr: Device MAC address
|
* @mac_addr: Device MAC address
|
||||||
|
@ -69,9 +72,7 @@ struct wps_credential {
|
||||||
* @model_name: Model Name (0..32 octets encoded in UTF-8)
|
* @model_name: Model Name (0..32 octets encoded in UTF-8)
|
||||||
* @model_number: Model Number (0..32 octets encoded in UTF-8)
|
* @model_number: Model Number (0..32 octets encoded in UTF-8)
|
||||||
* @serial_number: Serial Number (0..32 octets encoded in UTF-8)
|
* @serial_number: Serial Number (0..32 octets encoded in UTF-8)
|
||||||
* @categ: Primary Device Category
|
* @pri_dev_type: Primary Device Type
|
||||||
* @oui: Primary Device OUI
|
|
||||||
* @sub_categ: Primary Device Sub-Category
|
|
||||||
* @os_version: OS Version
|
* @os_version: OS Version
|
||||||
* @rf_bands: RF bands (WPS_RF_24GHZ, WPS_RF_50GHZ flags)
|
* @rf_bands: RF bands (WPS_RF_24GHZ, WPS_RF_50GHZ flags)
|
||||||
*/
|
*/
|
||||||
|
@ -82,9 +83,7 @@ struct wps_device_data {
|
||||||
char *model_name;
|
char *model_name;
|
||||||
char *model_number;
|
char *model_number;
|
||||||
char *serial_number;
|
char *serial_number;
|
||||||
u16 categ;
|
u8 pri_dev_type[WPS_DEV_TYPE_LEN];
|
||||||
u32 oui;
|
|
||||||
u16 sub_categ;
|
|
||||||
u32 os_version;
|
u32 os_version;
|
||||||
u8 rf_bands;
|
u8 rf_bands;
|
||||||
};
|
};
|
||||||
|
@ -684,4 +683,8 @@ int wps_er_pbc(struct wps_er *er, const u8 *uuid);
|
||||||
int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
|
int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
|
||||||
size_t pin_len);
|
size_t pin_len);
|
||||||
|
|
||||||
|
int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
|
||||||
|
char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
|
||||||
|
size_t buf_len);
|
||||||
|
|
||||||
#endif /* WPS_H */
|
#endif /* WPS_H */
|
||||||
|
|
|
@ -111,7 +111,7 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
|
||||||
attr->sel_reg_config_methods = pos;
|
attr->sel_reg_config_methods = pos;
|
||||||
break;
|
break;
|
||||||
case ATTR_PRIMARY_DEV_TYPE:
|
case ATTR_PRIMARY_DEV_TYPE:
|
||||||
if (len != sizeof(struct wps_dev_type)) {
|
if (len != WPS_DEV_TYPE_LEN) {
|
||||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
|
wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
|
||||||
"Type length %u", len);
|
"Type length %u", len);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -528,3 +528,41 @@ int wps_get_oob_method(char *method)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_WPS_OOB */
|
#endif /* CONFIG_WPS_OOB */
|
||||||
|
|
||||||
|
|
||||||
|
int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
|
||||||
|
{
|
||||||
|
const char *pos;
|
||||||
|
|
||||||
|
/* <categ>-<OUI>-<subcateg> */
|
||||||
|
WPA_PUT_BE16(dev_type, atoi(str));
|
||||||
|
pos = os_strchr(str, '-');
|
||||||
|
if (pos == NULL)
|
||||||
|
return -1;
|
||||||
|
pos++;
|
||||||
|
if (hexstr2bin(pos, &dev_type[2], 4))
|
||||||
|
return -1;
|
||||||
|
pos = os_strchr(pos, '-');
|
||||||
|
if (pos == NULL)
|
||||||
|
return -1;
|
||||||
|
pos++;
|
||||||
|
WPA_PUT_BE16(&dev_type[6], atoi(pos));
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
|
||||||
|
size_t buf_len)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
|
||||||
|
WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
|
||||||
|
WPA_GET_BE16(&dev_type[6]));
|
||||||
|
if (ret < 0 || (unsigned int) ret >= buf_len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
|
@ -232,13 +232,6 @@ enum wps_assoc_state {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Primary Device Type */
|
|
||||||
struct wps_dev_type {
|
|
||||||
u8 categ_id[2];
|
|
||||||
u8 oui[4];
|
|
||||||
u8 sub_categ_id[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define WPS_DEV_OUI_WFA 0x0050f204
|
#define WPS_DEV_OUI_WFA 0x0050f204
|
||||||
|
|
||||||
enum wps_dev_categ {
|
enum wps_dev_categ {
|
||||||
|
|
|
@ -113,14 +113,10 @@ static int wps_build_serial_number(struct wps_device_data *dev,
|
||||||
|
|
||||||
int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)
|
int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)
|
||||||
{
|
{
|
||||||
struct wps_dev_type *d;
|
|
||||||
wpa_printf(MSG_DEBUG, "WPS: * Primary Device Type");
|
wpa_printf(MSG_DEBUG, "WPS: * Primary Device Type");
|
||||||
wpabuf_put_be16(msg, ATTR_PRIMARY_DEV_TYPE);
|
wpabuf_put_be16(msg, ATTR_PRIMARY_DEV_TYPE);
|
||||||
wpabuf_put_be16(msg, sizeof(*d));
|
wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
|
||||||
d = wpabuf_put(msg, sizeof(*d));
|
wpabuf_put_data(msg, dev->pri_dev_type, WPS_DEV_TYPE_LEN);
|
||||||
WPA_PUT_BE16(d->categ_id, dev->categ);
|
|
||||||
WPA_PUT_BE32(d->oui, dev->oui);
|
|
||||||
WPA_PUT_BE16(d->sub_categ_id, dev->sub_categ);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,21 +284,17 @@ static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,
|
||||||
static int wps_process_primary_dev_type(struct wps_device_data *dev,
|
static int wps_process_primary_dev_type(struct wps_device_data *dev,
|
||||||
const u8 *dev_type)
|
const u8 *dev_type)
|
||||||
{
|
{
|
||||||
struct wps_dev_type *d;
|
char devtype[WPS_DEV_TYPE_BUFSIZE];
|
||||||
|
|
||||||
if (dev_type == NULL) {
|
if (dev_type == NULL) {
|
||||||
wpa_printf(MSG_DEBUG, "WPS: No Primary Device Type received");
|
wpa_printf(MSG_DEBUG, "WPS: No Primary Device Type received");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
d = (struct wps_dev_type *) dev_type;
|
os_memcpy(dev->pri_dev_type, dev_type, WPS_DEV_TYPE_LEN);
|
||||||
dev->categ = WPA_GET_BE16(d->categ_id);
|
wpa_printf(MSG_DEBUG, "WPS: Primary Device Type: %s",
|
||||||
dev->oui = WPA_GET_BE32(d->oui);
|
wps_dev_type_bin2str(dev->pri_dev_type, devtype,
|
||||||
dev->sub_categ = WPA_GET_BE16(d->sub_categ_id);
|
sizeof(devtype)));
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "WPS: Primary Device Type: category %d "
|
|
||||||
"OUI %08x sub-category %d",
|
|
||||||
dev->categ, dev->oui, dev->sub_categ);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -367,9 +359,7 @@ void wps_device_data_dup(struct wps_device_data *dst,
|
||||||
dst->model_number = os_strdup(src->model_number);
|
dst->model_number = os_strdup(src->model_number);
|
||||||
if (src->serial_number)
|
if (src->serial_number)
|
||||||
dst->serial_number = os_strdup(src->serial_number);
|
dst->serial_number = os_strdup(src->serial_number);
|
||||||
dst->categ = src->categ;
|
os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
|
||||||
dst->oui = src->oui;
|
|
||||||
dst->sub_categ = src->sub_categ;
|
|
||||||
dst->os_version = src->os_version;
|
dst->os_version = src->os_version;
|
||||||
dst->rf_bands = src->rf_bands;
|
dst->rf_bands = src->rf_bands;
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,9 +158,7 @@ static void wps_device_clone_data(struct wps_device_data *dst,
|
||||||
struct wps_device_data *src)
|
struct wps_device_data *src)
|
||||||
{
|
{
|
||||||
os_memcpy(dst->mac_addr, src->mac_addr, ETH_ALEN);
|
os_memcpy(dst->mac_addr, src->mac_addr, ETH_ALEN);
|
||||||
dst->categ = src->categ;
|
os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
|
||||||
dst->oui = src->oui;
|
|
||||||
dst->sub_categ = src->sub_categ;
|
|
||||||
|
|
||||||
#define WPS_STRDUP(n) \
|
#define WPS_STRDUP(n) \
|
||||||
os_free(dst->n); \
|
os_free(dst->n); \
|
||||||
|
@ -2800,6 +2798,7 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
|
||||||
struct wps_registrar_device *d;
|
struct wps_registrar_device *d;
|
||||||
int len = 0, ret;
|
int len = 0, ret;
|
||||||
char uuid[40];
|
char uuid[40];
|
||||||
|
char devtype[WPS_DEV_TYPE_BUFSIZE];
|
||||||
|
|
||||||
d = wps_device_get(reg, addr);
|
d = wps_device_get(reg, addr);
|
||||||
if (d == NULL)
|
if (d == NULL)
|
||||||
|
@ -2809,14 +2808,15 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
|
||||||
|
|
||||||
ret = os_snprintf(buf + len, buflen - len,
|
ret = os_snprintf(buf + len, buflen - len,
|
||||||
"wpsUuid=%s\n"
|
"wpsUuid=%s\n"
|
||||||
"wpsPrimaryDeviceType=%u-%08X-%u\n"
|
"wpsPrimaryDeviceType=%s\n"
|
||||||
"wpsDeviceName=%s\n"
|
"wpsDeviceName=%s\n"
|
||||||
"wpsManufacturer=%s\n"
|
"wpsManufacturer=%s\n"
|
||||||
"wpsModelName=%s\n"
|
"wpsModelName=%s\n"
|
||||||
"wpsModelNumber=%s\n"
|
"wpsModelNumber=%s\n"
|
||||||
"wpsSerialNumber=%s\n",
|
"wpsSerialNumber=%s\n",
|
||||||
uuid,
|
uuid,
|
||||||
d->dev.categ, d->dev.oui, d->dev.sub_categ,
|
wps_dev_type_bin2str(d->dev.pri_dev_type, devtype,
|
||||||
|
sizeof(devtype)),
|
||||||
d->dev.device_name ? d->dev.device_name : "",
|
d->dev.device_name ? d->dev.device_name : "",
|
||||||
d->dev.manufacturer ? d->dev.manufacturer : "",
|
d->dev.manufacturer ? d->dev.manufacturer : "",
|
||||||
d->dev.model_name ? d->dev.model_name : "",
|
d->dev.model_name ? d->dev.model_name : "",
|
||||||
|
|
|
@ -797,15 +797,17 @@ static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
|
||||||
{
|
{
|
||||||
char uuid[40], txt[400];
|
char uuid[40], txt[400];
|
||||||
int len;
|
int len;
|
||||||
|
char devtype[WPS_DEV_TYPE_BUFSIZE];
|
||||||
if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
|
if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
|
||||||
return;
|
return;
|
||||||
wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
|
wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
|
||||||
len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
|
len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
|
||||||
" [%s|%s|%s|%s|%s|%d-%08X-%d]",
|
" [%s|%s|%s|%s|%s|%s]",
|
||||||
uuid, MAC2STR(dev->mac_addr), dev->device_name,
|
uuid, MAC2STR(dev->mac_addr), dev->device_name,
|
||||||
dev->manufacturer, dev->model_name,
|
dev->manufacturer, dev->model_name,
|
||||||
dev->model_number, dev->serial_number,
|
dev->model_number, dev->serial_number,
|
||||||
dev->categ, dev->oui, dev->sub_categ);
|
wps_dev_type_bin2str(dev->pri_dev_type, devtype,
|
||||||
|
sizeof(devtype)));
|
||||||
if (len > 0 && len < (int) sizeof(txt))
|
if (len > 0 && len < (int) sizeof(txt))
|
||||||
wpa_printf(MSG_INFO, "%s", txt);
|
wpa_printf(MSG_INFO, "%s", txt);
|
||||||
}
|
}
|
||||||
|
@ -843,32 +845,12 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
|
||||||
wps->dev.model_name = wpa_s->conf->model_name;
|
wps->dev.model_name = wpa_s->conf->model_name;
|
||||||
wps->dev.model_number = wpa_s->conf->model_number;
|
wps->dev.model_number = wpa_s->conf->model_number;
|
||||||
wps->dev.serial_number = wpa_s->conf->serial_number;
|
wps->dev.serial_number = wpa_s->conf->serial_number;
|
||||||
if (wpa_s->conf->device_type) {
|
if (wpa_s->conf->device_type &&
|
||||||
char *pos;
|
wps_dev_type_str2bin(wpa_s->conf->device_type,
|
||||||
u8 oui[4];
|
wps->dev.pri_dev_type) < 0) {
|
||||||
/* <categ>-<OUI>-<subcateg> */
|
wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
|
||||||
wps->dev.categ = atoi(wpa_s->conf->device_type);
|
os_free(wps);
|
||||||
pos = os_strchr(wpa_s->conf->device_type, '-');
|
return -1;
|
||||||
if (pos == NULL) {
|
|
||||||
wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
|
|
||||||
os_free(wps);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
if (hexstr2bin(pos, oui, 4)) {
|
|
||||||
wpa_printf(MSG_ERROR, "WPS: Invalid device_type OUI");
|
|
||||||
os_free(wps);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
wps->dev.oui = WPA_GET_BE32(oui);
|
|
||||||
pos = os_strchr(pos, '-');
|
|
||||||
if (pos == NULL) {
|
|
||||||
wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
|
|
||||||
os_free(wps);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
wps->dev.sub_categ = atoi(pos);
|
|
||||||
}
|
}
|
||||||
wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
|
wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
|
||||||
wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; /* TODO: config */
|
wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; /* TODO: config */
|
||||||
|
|
Loading…
Reference in a new issue