@ -10887,6 +10887,456 @@ static int wpas_ctrl_iface_pasn_deauthenticate(struct wpa_supplicant *wpa_s,
# endif /* CONFIG_PASN */
static int set_type4_frame_classifier ( const char * cmd ,
struct type4_params * param )
{
const char * pos , * end ;
u8 classifier_mask = 0 ;
int ret ;
char addr [ INET6_ADDRSTRLEN ] ;
size_t alen ;
if ( os_strstr ( cmd , " ip_version=ipv4 " ) ) {
param - > ip_version = IPV4 ;
} else if ( os_strstr ( cmd , " ip_version=ipv6 " ) ) {
param - > ip_version = IPV6 ;
} else {
wpa_printf ( MSG_ERROR , " IP version missing/invalid " ) ;
return - 1 ;
}
classifier_mask | = BIT ( 0 ) ;
pos = os_strstr ( cmd , " src_ip= " ) ;
if ( pos ) {
pos + = 7 ;
end = os_strchr ( pos , ' ' ) ;
if ( ! end )
end = pos + os_strlen ( pos ) ;
alen = end - pos ;
if ( alen > = INET6_ADDRSTRLEN )
return - 1 ;
os_memcpy ( addr , pos , alen ) ;
addr [ alen ] = ' \0 ' ;
if ( param - > ip_version = = IPV4 )
ret = inet_pton ( AF_INET , addr ,
& param - > ip_params . v4 . src_ip ) ;
else
ret = inet_pton ( AF_INET6 , addr ,
& param - > ip_params . v6 . src_ip ) ;
if ( ret ! = 1 ) {
wpa_printf ( MSG_ERROR ,
" Error converting src IP address to binary ret=%d " ,
ret ) ;
return - 1 ;
}
classifier_mask | = BIT ( 1 ) ;
}
pos = os_strstr ( cmd , " dst_ip= " ) ;
if ( pos ) {
pos + = 7 ;
end = os_strchr ( pos , ' ' ) ;
if ( ! end )
end = pos + os_strlen ( pos ) ;
alen = end - pos ;
if ( alen > = INET6_ADDRSTRLEN )
return - 1 ;
os_memcpy ( addr , pos , alen ) ;
addr [ alen ] = ' \0 ' ;
if ( param - > ip_version = = IPV4 )
ret = inet_pton ( AF_INET , addr ,
& param - > ip_params . v4 . dst_ip ) ;
else
ret = inet_pton ( AF_INET6 , addr ,
& param - > ip_params . v6 . dst_ip ) ;
if ( ret ! = 1 ) {
wpa_printf ( MSG_ERROR ,
" Error converting dst IP address to binary ret=%d " ,
ret ) ;
return - 1 ;
}
classifier_mask | = BIT ( 2 ) ;
}
pos = os_strstr ( cmd , " src_port= " ) ;
if ( pos & & atoi ( pos + 9 ) > 0 ) {
if ( param - > ip_version = = IPV4 )
param - > ip_params . v4 . src_port = atoi ( pos + 9 ) ;
else
param - > ip_params . v6 . src_port = atoi ( pos + 9 ) ;
classifier_mask | = BIT ( 3 ) ;
}
pos = os_strstr ( cmd , " dst_port= " ) ;
if ( pos & & atoi ( pos + 9 ) > 0 ) {
if ( param - > ip_version = = IPV4 )
param - > ip_params . v4 . dst_port = atoi ( pos + 9 ) ;
else
param - > ip_params . v6 . dst_port = atoi ( pos + 9 ) ;
classifier_mask | = BIT ( 4 ) ;
}
pos = os_strstr ( cmd , " dscp= " ) ;
if ( pos & & atoi ( pos + 5 ) > 0 ) {
if ( param - > ip_version = = IPV4 )
param - > ip_params . v4 . dscp = atoi ( pos + 5 ) ;
else
param - > ip_params . v6 . dscp = atoi ( pos + 5 ) ;
classifier_mask | = BIT ( 5 ) ;
}
if ( param - > ip_version = = IPV4 ) {
pos = os_strstr ( cmd , " protocol= " ) ;
if ( pos ) {
if ( os_strstr ( pos , " udp " ) ) {
param - > ip_params . v4 . protocol = 17 ;
} else if ( os_strstr ( pos , " tcp " ) ) {
param - > ip_params . v4 . protocol = 6 ;
} else if ( os_strstr ( pos , " esp " ) ) {
param - > ip_params . v4 . protocol = 50 ;
} else {
wpa_printf ( MSG_ERROR , " Invalid protocol " ) ;
return - 1 ;
}
classifier_mask | = BIT ( 6 ) ;
}
} else {
pos = os_strstr ( cmd , " next_header= " ) ;
if ( pos ) {
if ( os_strstr ( pos , " udp " ) ) {
param - > ip_params . v6 . next_header = 17 ;
} else if ( os_strstr ( pos , " tcp " ) ) {
param - > ip_params . v6 . next_header = 6 ;
} else if ( os_strstr ( pos , " esp " ) ) {
param - > ip_params . v6 . next_header = 50 ;
} else {
wpa_printf ( MSG_ERROR , " Invalid next header " ) ;
return - 1 ;
}
classifier_mask | = BIT ( 6 ) ;
}
pos = os_strstr ( cmd , " flow_label= " ) ;
if ( pos ) {
pos + = 11 ;
end = os_strchr ( pos , ' ' ) ;
if ( ! end )
end = pos + os_strlen ( pos ) ;
if ( end - pos ! = 6 | |
hexstr2bin ( pos , param - > ip_params . v6 . flow_label ,
3 ) | |
param - > ip_params . v6 . flow_label [ 0 ] > 0x0F ) {
wpa_printf ( MSG_ERROR , " Invalid flow label " ) ;
return - 1 ;
}
classifier_mask | = BIT ( 7 ) ;
}
}
param - > classifier_mask = classifier_mask ;
return 0 ;
}
static int set_type10_frame_classifier ( const char * cmd ,
struct type10_params * param )
{
const char * pos , * end ;
size_t filter_len ;
pos = os_strstr ( cmd , " prot_instance= " ) ;
if ( ! pos ) {
wpa_printf ( MSG_ERROR , " Protocol instance missing " ) ;
return - 1 ;
}
param - > prot_instance = atoi ( pos + 14 ) ;
pos = os_strstr ( cmd , " prot_number= " ) ;
if ( ! pos ) {
wpa_printf ( MSG_ERROR , " Protocol number missing " ) ;
return - 1 ;
}
if ( os_strstr ( pos , " udp " ) ) {
param - > prot_number = 17 ;
} else if ( os_strstr ( pos , " tcp " ) ) {
param - > prot_number = 6 ;
} else if ( os_strstr ( pos , " esp " ) ) {
param - > prot_number = 50 ;
} else {
wpa_printf ( MSG_ERROR , " Invalid protocol number " ) ;
return - 1 ;
}
pos = os_strstr ( cmd , " filter_value= " ) ;
if ( ! pos ) {
wpa_printf ( MSG_ERROR ,
" Classifier parameter filter_value missing " ) ;
return - 1 ;
}
pos + = 13 ;
end = os_strchr ( pos , ' ' ) ;
if ( ! end )
end = pos + os_strlen ( pos ) ;
filter_len = ( end - pos ) / 2 ;
param - > filter_value = os_malloc ( filter_len ) ;
if ( ! param - > filter_value )
return - 1 ;
if ( hexstr2bin ( pos , param - > filter_value , filter_len ) ) {
wpa_printf ( MSG_ERROR , " Invalid filter_value %s " , pos ) ;
goto free ;
}
pos = os_strstr ( cmd , " filter_mask= " ) ;
if ( ! pos ) {
wpa_printf ( MSG_ERROR ,
" Classifier parameter filter_mask missing " ) ;
goto free ;
}
pos + = 12 ;
end = os_strchr ( pos , ' ' ) ;
if ( ! end )
end = pos + os_strlen ( pos ) ;
if ( filter_len ! = ( size_t ) ( end - pos ) / 2 ) {
wpa_printf ( MSG_ERROR ,
" Filter mask length mismatch expected=%zu received=%zu " ,
filter_len , ( size_t ) ( end - pos ) / 2 ) ;
goto free ;
}
param - > filter_mask = os_malloc ( filter_len ) ;
if ( ! param - > filter_mask )
goto free ;
if ( hexstr2bin ( pos , param - > filter_mask , filter_len ) ) {
wpa_printf ( MSG_ERROR , " Invalid filter mask %s " , pos ) ;
os_free ( param - > filter_mask ) ;
param - > filter_mask = NULL ;
goto free ;
}
param - > filter_len = filter_len ;
return 0 ;
free :
os_free ( param - > filter_value ) ;
param - > filter_value = NULL ;
return - 1 ;
}
static int scs_parse_type4 ( struct tclas_element * elem , const char * pos )
{
struct type4_params type4_param = { 0 } ;
if ( set_type4_frame_classifier ( pos , & type4_param ) = = - 1 ) {
wpa_printf ( MSG_ERROR , " Failed to set frame_classifier 4 " ) ;
return - 1 ;
}
os_memcpy ( & elem - > frame_classifier . type4_param ,
& type4_param , sizeof ( struct type4_params ) ) ;
return 0 ;
}
static int scs_parse_type10 ( struct tclas_element * elem , const char * pos )
{
struct type10_params type10_param = { 0 } ;
if ( set_type10_frame_classifier ( pos , & type10_param ) = = - 1 ) {
wpa_printf ( MSG_ERROR , " Failed to set frame_classifier 10 " ) ;
return - 1 ;
}
os_memcpy ( & elem - > frame_classifier . type10_param ,
& type10_param , sizeof ( struct type10_params ) ) ;
return 0 ;
}
static int wpas_ctrl_iface_configure_scs ( struct wpa_supplicant * wpa_s ,
char * cmd )
{
char * pos1 , * pos ;
struct scs_robust_av_data * scs_data = & wpa_s - > scs_robust_av_req ;
struct scs_desc_elem desc_elem = { 0 } ;
int val ;
unsigned int num_scs_desc = 0 ;
/**
* format :
* [ scs_id = < decimal number > ] < add | remove | change > [ scs_up = < 0 - 7 > ]
* [ classifier_type = < 4 | 10 > ]
* [ classifier params based on classifier type ]
* [ tclas_processing = < 0 | 1 > ] [ scs_id = < decimal number > ] . . .
*/
pos1 = os_strstr ( cmd , " scs_id= " ) ;
if ( ! pos1 ) {
wpa_printf ( MSG_ERROR , " SCSID not present " ) ;
return - 1 ;
}
free_up_scs_desc ( scs_data ) ;
while ( pos1 ) {
struct scs_desc_elem * n1 ;
char * next_scs_desc ;
unsigned int num_tclas_elem = 0 ;
desc_elem . scs_id = atoi ( pos1 + 7 ) ;
pos1 + = 7 ;
next_scs_desc = os_strstr ( pos1 , " scs_id= " ) ;
if ( next_scs_desc ) {
char temp [ 20 ] ;
os_snprintf ( temp , sizeof ( temp ) , " scs_id=%d " ,
desc_elem . scs_id ) ;
if ( os_strstr ( next_scs_desc , temp ) ) {
wpa_printf ( MSG_ERROR ,
" Multiple SCS descriptors configured with same SCSID(=%d) " ,
desc_elem . scs_id ) ;
goto free_scs_desc ;
}
pos1 [ next_scs_desc - pos1 - 1 ] = ' \0 ' ;
}
if ( os_strstr ( pos1 , " add " ) ) {
desc_elem . request_type = SCS_REQ_ADD ;
} else if ( os_strstr ( pos1 , " remove " ) ) {
desc_elem . request_type = SCS_REQ_REMOVE ;
goto scs_desc_end ;
} else if ( os_strstr ( pos1 , " change " ) ) {
desc_elem . request_type = SCS_REQ_CHANGE ;
} else {
wpa_printf ( MSG_ERROR , " SCS Request type invalid " ) ;
goto free_scs_desc ;
}
pos1 = os_strstr ( pos1 , " scs_up= " ) ;
if ( ! pos1 ) {
wpa_printf ( MSG_ERROR ,
" Intra-Access user priority not present " ) ;
goto free_scs_desc ;
}
val = atoi ( pos1 + 7 ) ;
if ( val < 0 | | val > 7 ) {
wpa_printf ( MSG_ERROR ,
" Intra-Access user priority invalid %d " ,
val ) ;
goto free_scs_desc ;
}
desc_elem . intra_access_priority = val ;
desc_elem . scs_up_avail = true ;
pos = os_strstr ( pos1 , " classifier_type= " ) ;
if ( ! pos ) {
wpa_printf ( MSG_ERROR , " classifier type empty " ) ;
goto free_scs_desc ;
}
while ( pos ) {
struct tclas_element elem = { 0 } , * n ;
char * next_tclas_elem ;
val = atoi ( pos + 16 ) ;
if ( val ! = 4 & & val ! = 10 ) {
wpa_printf ( MSG_ERROR ,
" classifier type invalid %d " , val ) ;
goto free_scs_desc ;
}
elem . classifier_type = val ;
pos + = 16 ;
next_tclas_elem = os_strstr ( pos , " classifier_type= " ) ;
if ( next_tclas_elem ) {
pos1 = next_tclas_elem ;
pos [ next_tclas_elem - pos - 1 ] = ' \0 ' ;
}
switch ( val ) {
case 4 :
if ( scs_parse_type4 ( & elem , pos ) < 0 )
goto free_scs_desc ;
break ;
case 10 :
if ( scs_parse_type10 ( & elem , pos ) < 0 )
goto free_scs_desc ;
break ;
}
n = os_realloc ( desc_elem . tclas_elems ,
( num_tclas_elem + 1 ) * sizeof ( elem ) ) ;
if ( ! n )
goto free_scs_desc ;
desc_elem . tclas_elems = n ;
os_memcpy ( ( u8 * ) desc_elem . tclas_elems +
num_tclas_elem * sizeof ( elem ) ,
& elem , sizeof ( elem ) ) ;
num_tclas_elem + + ;
desc_elem . num_tclas_elem = num_tclas_elem ;
pos = next_tclas_elem ;
}
if ( desc_elem . num_tclas_elem > 1 ) {
pos1 = os_strstr ( pos1 , " tclas_processing= " ) ;
if ( ! pos1 ) {
wpa_printf ( MSG_ERROR , " tclas_processing empty " ) ;
goto free_scs_desc ;
}
val = atoi ( pos1 + 17 ) ;
if ( val ! = 0 & & val ! = 1 ) {
wpa_printf ( MSG_ERROR ,
" tclas_processing invalid " ) ;
goto free_scs_desc ;
}
desc_elem . tclas_processing = val ;
}
scs_desc_end :
n1 = os_realloc ( scs_data - > scs_desc_elems , ( num_scs_desc + 1 ) *
sizeof ( struct scs_desc_elem ) ) ;
if ( ! n1 )
goto free_scs_desc ;
scs_data - > scs_desc_elems = n1 ;
os_memcpy ( ( u8 * ) scs_data - > scs_desc_elems + num_scs_desc *
sizeof ( desc_elem ) , & desc_elem , sizeof ( desc_elem ) ) ;
num_scs_desc + + ;
scs_data - > num_scs_desc = num_scs_desc ;
pos1 = next_scs_desc ;
os_memset ( & desc_elem , 0 , sizeof ( desc_elem ) ) ;
}
return wpas_send_scs_req ( wpa_s ) ;
free_scs_desc :
free_up_tclas_elem ( & desc_elem ) ;
free_up_scs_desc ( scs_data ) ;
return - 1 ;
}
char * wpa_supplicant_ctrl_iface_process ( struct wpa_supplicant * wpa_s ,
char * buf , size_t * resp_len )
{
@ -11812,6 +12262,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if ( wpas_ctrl_iface_pasn_deauthenticate ( wpa_s , buf + 12 ) < 0 )
reply_len = - 1 ;
# endif /* CONFIG_PASN */
} else if ( os_strncmp ( buf , " SCS " , 4 ) = = 0 ) {
if ( wpas_ctrl_iface_configure_scs ( wpa_s , buf + 4 ) )
reply_len = - 1 ;
} else {
os_memcpy ( reply , " UNKNOWN COMMAND \n " , 16 ) ;
reply_len = 16 ;