2020-03-27 14:48:52 -07:00
// SPDX-License-Identifier: GPL-2.0
# include <errno.h>
# include <error.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
2022-05-03 19:38:53 -07:00
# include <limits.h>
2020-03-27 14:48:52 -07:00
# include <sys/socket.h>
# include <sys/types.h>
# include <arpa/inet.h>
# include <net/if.h>
# include <linux/rtnetlink.h>
# include <linux/genetlink.h>
# include "linux/mptcp.h"
# ifndef MPTCP_PM_NAME
# define MPTCP_PM_NAME "mptcp_pm"
# endif
static void syntax ( char * argv [ ] )
{
2021-01-08 16:48:00 -08:00
fprintf ( stderr , " %s add|get|set|del|flush|dump|accept [<args>] \n " , argv [ 0 ] ) ;
2021-08-17 15:07:25 -07:00
fprintf ( stderr , " \t add [flags signal|subflow|backup|fullmesh] [id <nr>] [dev <name>] <ip> \n " ) ;
2022-05-03 19:38:53 -07:00
fprintf ( stderr , " \t ann <local-ip> id <local-id> token <token> [port <local-port>] [dev <name>] \n " ) ;
2022-05-03 19:38:55 -07:00
fprintf ( stderr , " \t rem id <local-id> token <token> \n " ) ;
2022-05-03 19:38:57 -07:00
fprintf ( stderr , " \t csf lip <local-ip> lid <local-id> rip <remote-ip> rport <remote-port> token <token> \n " ) ;
2022-05-03 19:38:58 -07:00
fprintf ( stderr , " \t dsf lip <local-ip> lport <local-port> rip <remote-ip> rport <remote-port> token <token> \n " ) ;
2021-03-30 17:08:55 -07:00
fprintf ( stderr , " \t del <id> [<ip>] \n " ) ;
2020-03-27 14:48:52 -07:00
fprintf ( stderr , " \t get <id> \n " ) ;
2022-02-04 16:03:35 -08:00
fprintf ( stderr , " \t set [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>] \n " ) ;
2020-03-27 14:48:52 -07:00
fprintf ( stderr , " \t flush \n " ) ;
fprintf ( stderr , " \t dump \n " ) ;
fprintf ( stderr , " \t limits [<rcv addr max> <subflow max>] \n " ) ;
exit ( 0 ) ;
}
static int init_genl_req ( char * data , int family , int cmd , int version )
{
struct nlmsghdr * nh = ( void * ) data ;
struct genlmsghdr * gh ;
int off = 0 ;
nh - > nlmsg_type = family ;
nh - > nlmsg_flags = NLM_F_REQUEST ;
nh - > nlmsg_len = NLMSG_LENGTH ( GENL_HDRLEN ) ;
off + = NLMSG_ALIGN ( sizeof ( * nh ) ) ;
gh = ( void * ) ( data + off ) ;
gh - > cmd = cmd ;
gh - > version = version ;
off + = NLMSG_ALIGN ( sizeof ( * gh ) ) ;
return off ;
}
static void nl_error ( struct nlmsghdr * nh )
{
struct nlmsgerr * err = ( struct nlmsgerr * ) NLMSG_DATA ( nh ) ;
int len = nh - > nlmsg_len - sizeof ( * nh ) ;
uint32_t off ;
if ( len < sizeof ( struct nlmsgerr ) )
error ( 1 , 0 , " netlink error message truncated %d min %ld " , len ,
sizeof ( struct nlmsgerr ) ) ;
if ( ! err - > error ) {
/* check messages from kernel */
struct rtattr * attrs = ( struct rtattr * ) NLMSG_DATA ( nh ) ;
while ( RTA_OK ( attrs , len ) ) {
if ( attrs - > rta_type = = NLMSGERR_ATTR_MSG )
fprintf ( stderr , " netlink ext ack msg: %s \n " ,
( char * ) RTA_DATA ( attrs ) ) ;
if ( attrs - > rta_type = = NLMSGERR_ATTR_OFFS ) {
memcpy ( & off , RTA_DATA ( attrs ) , 4 ) ;
fprintf ( stderr , " netlink err off %d \n " ,
( int ) off ) ;
}
attrs = RTA_NEXT ( attrs , len ) ;
}
} else {
fprintf ( stderr , " netlink error %d " , err - > error ) ;
}
}
/* do a netlink command and, if max > 0, fetch the reply */
static int do_nl_req ( int fd , struct nlmsghdr * nh , int len , int max )
{
struct sockaddr_nl nladdr = { . nl_family = AF_NETLINK } ;
socklen_t addr_len ;
void * data = nh ;
int rem , ret ;
int err = 0 ;
nh - > nlmsg_len = len ;
ret = sendto ( fd , data , len , 0 , ( void * ) & nladdr , sizeof ( nladdr ) ) ;
if ( ret ! = len )
error ( 1 , errno , " send netlink: %uB != %uB \n " , ret , len ) ;
if ( max = = 0 )
return 0 ;
addr_len = sizeof ( nladdr ) ;
rem = ret = recvfrom ( fd , data , max , 0 , ( void * ) & nladdr , & addr_len ) ;
if ( ret < 0 )
error ( 1 , errno , " recv netlink: %uB \n " , ret ) ;
/* Beware: the NLMSG_NEXT macro updates the 'rem' argument */
for ( ; NLMSG_OK ( nh , rem ) ; nh = NLMSG_NEXT ( nh , rem ) ) {
if ( nh - > nlmsg_type = = NLMSG_ERROR ) {
nl_error ( nh ) ;
err = 1 ;
}
}
if ( err )
error ( 1 , 0 , " bailing out due to netlink error[s] " ) ;
return ret ;
}
static int genl_parse_getfamily ( struct nlmsghdr * nlh )
{
struct genlmsghdr * ghdr = NLMSG_DATA ( nlh ) ;
int len = nlh - > nlmsg_len ;
struct rtattr * attrs ;
if ( nlh - > nlmsg_type ! = GENL_ID_CTRL )
error ( 1 , errno , " Not a controller message, len=%d type=0x%x \n " ,
nlh - > nlmsg_len , nlh - > nlmsg_type ) ;
len - = NLMSG_LENGTH ( GENL_HDRLEN ) ;
if ( len < 0 )
error ( 1 , errno , " wrong controller message len %d \n " , len ) ;
if ( ghdr - > cmd ! = CTRL_CMD_NEWFAMILY )
error ( 1 , errno , " Unknown controller command %d \n " , ghdr - > cmd ) ;
attrs = ( struct rtattr * ) ( ( char * ) ghdr + GENL_HDRLEN ) ;
while ( RTA_OK ( attrs , len ) ) {
if ( attrs - > rta_type = = CTRL_ATTR_FAMILY_ID )
return * ( __u16 * ) RTA_DATA ( attrs ) ;
attrs = RTA_NEXT ( attrs , len ) ;
}
error ( 1 , errno , " can't find CTRL_ATTR_FAMILY_ID attr " ) ;
return - 1 ;
}
static int resolve_mptcp_pm_netlink ( int fd )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
struct nlmsghdr * nh ;
struct rtattr * rta ;
int namelen ;
int off = 0 ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , GENL_ID_CTRL , CTRL_CMD_GETFAMILY , 0 ) ;
rta = ( void * ) ( data + off ) ;
namelen = strlen ( MPTCP_PM_NAME ) + 1 ;
rta - > rta_type = CTRL_ATTR_FAMILY_NAME ;
rta - > rta_len = RTA_LENGTH ( namelen ) ;
memcpy ( RTA_DATA ( rta ) , MPTCP_PM_NAME , namelen ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
do_nl_req ( fd , nh , off , sizeof ( data ) ) ;
return genl_parse_getfamily ( ( void * ) data ) ;
}
2022-05-03 19:38:58 -07:00
int dsf ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
struct rtattr * rta , * addr ;
u_int16_t family , port ;
struct nlmsghdr * nh ;
u_int32_t token ;
int addr_start ;
int off = 0 ;
int arg ;
const char * params [ 5 ] ;
memset ( params , 0 , 5 * sizeof ( const char * ) ) ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_SUBFLOW_DESTROY ,
MPTCP_PM_VER ) ;
if ( argc < 12 )
syntax ( argv ) ;
/* Params recorded in this order:
* < local - ip > , < local - port > , < remote - ip > , < remote - port > , < token >
*/
for ( arg = 2 ; arg < argc ; arg + + ) {
if ( ! strcmp ( argv [ arg ] , " lip " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing local IP " ) ;
params [ 0 ] = argv [ arg ] ;
} else if ( ! strcmp ( argv [ arg ] , " lport " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing local port " ) ;
params [ 1 ] = argv [ arg ] ;
} else if ( ! strcmp ( argv [ arg ] , " rip " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing remote IP " ) ;
params [ 2 ] = argv [ arg ] ;
} else if ( ! strcmp ( argv [ arg ] , " rport " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing remote port " ) ;
params [ 3 ] = argv [ arg ] ;
} else if ( ! strcmp ( argv [ arg ] , " token " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing token " ) ;
params [ 4 ] = argv [ arg ] ;
} else
error ( 1 , 0 , " unknown keyword %s " , argv [ arg ] ) ;
}
for ( arg = 0 ; arg < 4 ; arg = arg + 2 ) {
/* addr header */
addr_start = off ;
addr = ( void * ) ( data + off ) ;
addr - > rta_type = NLA_F_NESTED |
( ( arg = = 0 ) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE ) ;
addr - > rta_len = RTA_LENGTH ( 0 ) ;
off + = NLMSG_ALIGN ( addr - > rta_len ) ;
/* addr data */
rta = ( void * ) ( data + off ) ;
if ( inet_pton ( AF_INET , params [ arg ] , RTA_DATA ( rta ) ) ) {
family = AF_INET ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR4 ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
} else if ( inet_pton ( AF_INET6 , params [ arg ] , RTA_DATA ( rta ) ) ) {
family = AF_INET6 ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR6 ;
rta - > rta_len = RTA_LENGTH ( 16 ) ;
} else
error ( 1 , errno , " can't parse ip %s " , params [ arg ] ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
/* family */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_FAMILY ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & family , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
/* port */
port = atoi ( params [ arg + 1 ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_PORT ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & port , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
addr - > rta_len = off - addr_start ;
}
/* token */
token = atoi ( params [ 4 ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ATTR_TOKEN ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & token , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
do_nl_req ( fd , nh , off , 0 ) ;
return 0 ;
}
2022-05-03 19:38:57 -07:00
int csf ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
const char * params [ 5 ] ;
struct nlmsghdr * nh ;
struct rtattr * addr ;
struct rtattr * rta ;
u_int16_t family ;
u_int32_t token ;
u_int16_t port ;
int addr_start ;
u_int8_t id ;
int off = 0 ;
int arg ;
memset ( params , 0 , 5 * sizeof ( const char * ) ) ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_SUBFLOW_CREATE ,
MPTCP_PM_VER ) ;
if ( argc < 12 )
syntax ( argv ) ;
/* Params recorded in this order:
* < local - ip > , < local - id > , < remote - ip > , < remote - port > , < token >
*/
for ( arg = 2 ; arg < argc ; arg + + ) {
if ( ! strcmp ( argv [ arg ] , " lip " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing local IP " ) ;
params [ 0 ] = argv [ arg ] ;
} else if ( ! strcmp ( argv [ arg ] , " lid " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing local id " ) ;
params [ 1 ] = argv [ arg ] ;
} else if ( ! strcmp ( argv [ arg ] , " rip " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing remote ip " ) ;
params [ 2 ] = argv [ arg ] ;
} else if ( ! strcmp ( argv [ arg ] , " rport " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing remote port " ) ;
params [ 3 ] = argv [ arg ] ;
} else if ( ! strcmp ( argv [ arg ] , " token " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing token " ) ;
params [ 4 ] = argv [ arg ] ;
} else
error ( 1 , 0 , " unknown param %s " , argv [ arg ] ) ;
}
for ( arg = 0 ; arg < 4 ; arg = arg + 2 ) {
/* addr header */
addr_start = off ;
addr = ( void * ) ( data + off ) ;
addr - > rta_type = NLA_F_NESTED |
( ( arg = = 0 ) ? MPTCP_PM_ATTR_ADDR : MPTCP_PM_ATTR_ADDR_REMOTE ) ;
addr - > rta_len = RTA_LENGTH ( 0 ) ;
off + = NLMSG_ALIGN ( addr - > rta_len ) ;
/* addr data */
rta = ( void * ) ( data + off ) ;
if ( inet_pton ( AF_INET , params [ arg ] , RTA_DATA ( rta ) ) ) {
family = AF_INET ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR4 ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
} else if ( inet_pton ( AF_INET6 , params [ arg ] , RTA_DATA ( rta ) ) ) {
family = AF_INET6 ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR6 ;
rta - > rta_len = RTA_LENGTH ( 16 ) ;
} else
error ( 1 , errno , " can't parse ip %s " , params [ arg ] ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
/* family */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_FAMILY ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & family , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
if ( arg = = 2 ) {
/* port */
port = atoi ( params [ arg + 1 ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_PORT ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & port , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
}
if ( arg = = 0 ) {
/* id */
id = atoi ( params [ arg + 1 ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ID ;
rta - > rta_len = RTA_LENGTH ( 1 ) ;
memcpy ( RTA_DATA ( rta ) , & id , 1 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
}
addr - > rta_len = off - addr_start ;
}
/* token */
token = atoi ( params [ 4 ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ATTR_TOKEN ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & token , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
do_nl_req ( fd , nh , off , 0 ) ;
return 0 ;
}
2022-05-03 19:38:55 -07:00
int remove_addr ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
struct nlmsghdr * nh ;
struct rtattr * rta ;
u_int32_t token ;
u_int8_t id ;
int off = 0 ;
int arg ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_REMOVE ,
MPTCP_PM_VER ) ;
if ( argc < 6 )
syntax ( argv ) ;
for ( arg = 2 ; arg < argc ; arg + + ) {
if ( ! strcmp ( argv [ arg ] , " id " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing id value " ) ;
id = atoi ( argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ATTR_LOC_ID ;
rta - > rta_len = RTA_LENGTH ( 1 ) ;
memcpy ( RTA_DATA ( rta ) , & id , 1 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
} else if ( ! strcmp ( argv [ arg ] , " token " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing token value " ) ;
token = atoi ( argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ATTR_TOKEN ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & token , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
} else
error ( 1 , 0 , " unknown keyword %s " , argv [ arg ] ) ;
}
do_nl_req ( fd , nh , off , 0 ) ;
return 0 ;
}
2022-05-03 19:38:53 -07:00
int announce_addr ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
u_int32_t flags = MPTCP_PM_ADDR_FLAG_SIGNAL ;
u_int32_t token = UINT_MAX ;
struct rtattr * rta , * addr ;
u_int32_t id = UINT_MAX ;
struct nlmsghdr * nh ;
u_int16_t family ;
int addr_start ;
int off = 0 ;
int arg ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_ANNOUNCE ,
MPTCP_PM_VER ) ;
if ( argc < 7 )
syntax ( argv ) ;
/* local-ip header */
addr_start = off ;
addr = ( void * ) ( data + off ) ;
addr - > rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR ;
addr - > rta_len = RTA_LENGTH ( 0 ) ;
off + = NLMSG_ALIGN ( addr - > rta_len ) ;
/* local-ip data */
/* record addr type */
rta = ( void * ) ( data + off ) ;
if ( inet_pton ( AF_INET , argv [ 2 ] , RTA_DATA ( rta ) ) ) {
family = AF_INET ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR4 ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
} else if ( inet_pton ( AF_INET6 , argv [ 2 ] , RTA_DATA ( rta ) ) ) {
family = AF_INET6 ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR6 ;
rta - > rta_len = RTA_LENGTH ( 16 ) ;
} else
error ( 1 , errno , " can't parse ip %s " , argv [ 2 ] ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
/* addr family */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_FAMILY ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & family , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
for ( arg = 3 ; arg < argc ; arg + + ) {
if ( ! strcmp ( argv [ arg ] , " id " ) ) {
/* local-id */
if ( + + arg > = argc )
error ( 1 , 0 , " missing id value " ) ;
id = atoi ( argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ID ;
rta - > rta_len = RTA_LENGTH ( 1 ) ;
memcpy ( RTA_DATA ( rta ) , & id , 1 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
} else if ( ! strcmp ( argv [ arg ] , " dev " ) ) {
/* for the if_index */
int32_t ifindex ;
if ( + + arg > = argc )
error ( 1 , 0 , " missing dev name " ) ;
ifindex = if_nametoindex ( argv [ arg ] ) ;
if ( ! ifindex )
error ( 1 , errno , " unknown device %s " , argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & ifindex , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
} else if ( ! strcmp ( argv [ arg ] , " port " ) ) {
/* local-port (optional) */
u_int16_t port ;
if ( + + arg > = argc )
error ( 1 , 0 , " missing port value " ) ;
port = atoi ( argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_PORT ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & port , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
} else if ( ! strcmp ( argv [ arg ] , " token " ) ) {
/* MPTCP connection token */
if ( + + arg > = argc )
error ( 1 , 0 , " missing token value " ) ;
token = atoi ( argv [ arg ] ) ;
} else
error ( 1 , 0 , " unknown keyword %s " , argv [ arg ] ) ;
}
/* addr flags */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_FLAGS ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & flags , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
addr - > rta_len = off - addr_start ;
if ( id = = UINT_MAX | | token = = UINT_MAX )
error ( 1 , 0 , " missing mandatory inputs " ) ;
/* token */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ATTR_TOKEN ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & token , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
do_nl_req ( fd , nh , off , 0 ) ;
return 0 ;
}
2020-03-27 14:48:52 -07:00
int add_addr ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
struct rtattr * rta , * nest ;
struct nlmsghdr * nh ;
2021-02-01 15:09:18 -08:00
u_int32_t flags = 0 ;
2020-03-27 14:48:52 -07:00
u_int16_t family ;
int nest_start ;
u_int8_t id ;
int off = 0 ;
int arg ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_ADD_ADDR ,
MPTCP_PM_VER ) ;
if ( argc < 3 )
syntax ( argv ) ;
nest_start = off ;
nest = ( void * ) ( data + off ) ;
nest - > rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR ;
nest - > rta_len = RTA_LENGTH ( 0 ) ;
off + = NLMSG_ALIGN ( nest - > rta_len ) ;
/* addr data */
rta = ( void * ) ( data + off ) ;
if ( inet_pton ( AF_INET , argv [ 2 ] , RTA_DATA ( rta ) ) ) {
family = AF_INET ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR4 ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
} else if ( inet_pton ( AF_INET6 , argv [ 2 ] , RTA_DATA ( rta ) ) ) {
family = AF_INET6 ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR6 ;
rta - > rta_len = RTA_LENGTH ( 16 ) ;
} else
error ( 1 , errno , " can't parse ip %s " , argv [ 2 ] ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
/* family */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_FAMILY ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & family , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
for ( arg = 3 ; arg < argc ; arg + + ) {
if ( ! strcmp ( argv [ arg ] , " flags " ) ) {
char * tok , * str ;
/* flags */
if ( + + arg > = argc )
error ( 1 , 0 , " missing flags value " ) ;
/* do not support flag list yet */
for ( str = argv [ arg ] ; ( tok = strtok ( str , " , " ) ) ;
str = NULL ) {
if ( ! strcmp ( tok , " subflow " ) )
flags | = MPTCP_PM_ADDR_FLAG_SUBFLOW ;
else if ( ! strcmp ( tok , " signal " ) )
flags | = MPTCP_PM_ADDR_FLAG_SIGNAL ;
else if ( ! strcmp ( tok , " backup " ) )
flags | = MPTCP_PM_ADDR_FLAG_BACKUP ;
2021-08-17 15:07:25 -07:00
else if ( ! strcmp ( tok , " fullmesh " ) )
flags | = MPTCP_PM_ADDR_FLAG_FULLMESH ;
2020-03-27 14:48:52 -07:00
else
error ( 1 , errno ,
" unknown flag %s " , argv [ arg ] ) ;
}
2021-08-17 15:07:25 -07:00
if ( flags & MPTCP_PM_ADDR_FLAG_SIGNAL & &
flags & MPTCP_PM_ADDR_FLAG_FULLMESH ) {
error ( 1 , errno , " error flag fullmesh " ) ;
}
2020-03-27 14:48:52 -07:00
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_FLAGS ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & flags , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
} else if ( ! strcmp ( argv [ arg ] , " id " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing id value " ) ;
id = atoi ( argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ID ;
rta - > rta_len = RTA_LENGTH ( 1 ) ;
memcpy ( RTA_DATA ( rta ) , & id , 1 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
} else if ( ! strcmp ( argv [ arg ] , " dev " ) ) {
int32_t ifindex ;
if ( + + arg > = argc )
error ( 1 , 0 , " missing dev name " ) ;
ifindex = if_nametoindex ( argv [ arg ] ) ;
if ( ! ifindex )
error ( 1 , errno , " unknown device %s " , argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_IF_IDX ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & ifindex , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
2021-02-01 15:09:18 -08:00
} else if ( ! strcmp ( argv [ arg ] , " port " ) ) {
u_int16_t port ;
if ( + + arg > = argc )
error ( 1 , 0 , " missing port value " ) ;
if ( ! ( flags & MPTCP_PM_ADDR_FLAG_SIGNAL ) )
error ( 1 , 0 , " flags must be signal when using port " ) ;
port = atoi ( argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_PORT ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & port , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
2020-03-27 14:48:52 -07:00
} else
error ( 1 , 0 , " unknown keyword %s " , argv [ arg ] ) ;
}
nest - > rta_len = off - nest_start ;
do_nl_req ( fd , nh , off , 0 ) ;
return 0 ;
}
int del_addr ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
struct rtattr * rta , * nest ;
struct nlmsghdr * nh ;
2021-03-30 17:08:55 -07:00
u_int16_t family ;
2020-03-27 14:48:52 -07:00
int nest_start ;
u_int8_t id ;
int off = 0 ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_DEL_ADDR ,
MPTCP_PM_VER ) ;
2021-03-30 17:08:55 -07:00
/* the only argument is the address id (nonzero) */
if ( argc ! = 3 & & argc ! = 4 )
2020-03-27 14:48:52 -07:00
syntax ( argv ) ;
id = atoi ( argv [ 2 ] ) ;
2021-03-30 17:08:55 -07:00
/* zero id with the IP address */
if ( ! id & & argc ! = 4 )
syntax ( argv ) ;
2020-03-27 14:48:52 -07:00
nest_start = off ;
nest = ( void * ) ( data + off ) ;
nest - > rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR ;
nest - > rta_len = RTA_LENGTH ( 0 ) ;
off + = NLMSG_ALIGN ( nest - > rta_len ) ;
/* build a dummy addr with only the ID set */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ID ;
rta - > rta_len = RTA_LENGTH ( 1 ) ;
memcpy ( RTA_DATA ( rta ) , & id , 1 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
2021-03-30 17:08:55 -07:00
if ( ! id ) {
/* addr data */
rta = ( void * ) ( data + off ) ;
if ( inet_pton ( AF_INET , argv [ 3 ] , RTA_DATA ( rta ) ) ) {
family = AF_INET ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR4 ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
} else if ( inet_pton ( AF_INET6 , argv [ 3 ] , RTA_DATA ( rta ) ) ) {
family = AF_INET6 ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR6 ;
rta - > rta_len = RTA_LENGTH ( 16 ) ;
} else {
error ( 1 , errno , " can't parse ip %s " , argv [ 3 ] ) ;
}
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
/* family */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_FAMILY ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & family , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
}
2020-03-27 14:48:52 -07:00
nest - > rta_len = off - nest_start ;
do_nl_req ( fd , nh , off , 0 ) ;
return 0 ;
}
static void print_addr ( struct rtattr * attrs , int len )
{
uint16_t family = 0 ;
2021-02-01 15:09:18 -08:00
uint16_t port = 0 ;
2020-03-27 14:48:52 -07:00
char str [ 1024 ] ;
uint32_t flags ;
uint8_t id ;
while ( RTA_OK ( attrs , len ) ) {
if ( attrs - > rta_type = = MPTCP_PM_ADDR_ATTR_FAMILY )
memcpy ( & family , RTA_DATA ( attrs ) , 2 ) ;
2021-02-01 15:09:18 -08:00
if ( attrs - > rta_type = = MPTCP_PM_ADDR_ATTR_PORT )
memcpy ( & port , RTA_DATA ( attrs ) , 2 ) ;
2020-03-27 14:48:52 -07:00
if ( attrs - > rta_type = = MPTCP_PM_ADDR_ATTR_ADDR4 ) {
if ( family ! = AF_INET )
error ( 1 , errno , " wrong IP (v4) for family %d " ,
family ) ;
inet_ntop ( AF_INET , RTA_DATA ( attrs ) , str , sizeof ( str ) ) ;
2020-03-30 16:23:54 +02:00
printf ( " %s " , str ) ;
2021-02-01 15:09:18 -08:00
if ( port )
printf ( " %d " , port ) ;
2020-03-27 14:48:52 -07:00
}
if ( attrs - > rta_type = = MPTCP_PM_ADDR_ATTR_ADDR6 ) {
if ( family ! = AF_INET6 )
error ( 1 , errno , " wrong IP (v6) for family %d " ,
family ) ;
inet_ntop ( AF_INET6 , RTA_DATA ( attrs ) , str , sizeof ( str ) ) ;
2020-03-30 16:23:54 +02:00
printf ( " %s " , str ) ;
2021-02-01 15:09:18 -08:00
if ( port )
printf ( " %d " , port ) ;
2020-03-27 14:48:52 -07:00
}
if ( attrs - > rta_type = = MPTCP_PM_ADDR_ATTR_ID ) {
memcpy ( & id , RTA_DATA ( attrs ) , 1 ) ;
printf ( " id %d " , id ) ;
}
if ( attrs - > rta_type = = MPTCP_PM_ADDR_ATTR_FLAGS ) {
memcpy ( & flags , RTA_DATA ( attrs ) , 4 ) ;
printf ( " flags " ) ;
if ( flags & MPTCP_PM_ADDR_FLAG_SIGNAL ) {
printf ( " signal " ) ;
flags & = ~ MPTCP_PM_ADDR_FLAG_SIGNAL ;
if ( flags )
printf ( " , " ) ;
}
if ( flags & MPTCP_PM_ADDR_FLAG_SUBFLOW ) {
printf ( " subflow " ) ;
flags & = ~ MPTCP_PM_ADDR_FLAG_SUBFLOW ;
if ( flags )
printf ( " , " ) ;
}
if ( flags & MPTCP_PM_ADDR_FLAG_BACKUP ) {
printf ( " backup " ) ;
flags & = ~ MPTCP_PM_ADDR_FLAG_BACKUP ;
if ( flags )
printf ( " , " ) ;
}
2021-08-17 15:07:25 -07:00
if ( flags & MPTCP_PM_ADDR_FLAG_FULLMESH ) {
printf ( " fullmesh " ) ;
flags & = ~ MPTCP_PM_ADDR_FLAG_FULLMESH ;
if ( flags )
printf ( " , " ) ;
}
2022-03-07 12:44:38 -08:00
if ( flags & MPTCP_PM_ADDR_FLAG_IMPLICIT ) {
printf ( " implicit " ) ;
flags & = ~ MPTCP_PM_ADDR_FLAG_IMPLICIT ;
if ( flags )
printf ( " , " ) ;
}
2020-03-27 14:48:52 -07:00
/* bump unknown flags, if any */
if ( flags )
printf ( " 0x%x " , flags ) ;
printf ( " " ) ;
}
if ( attrs - > rta_type = = MPTCP_PM_ADDR_ATTR_IF_IDX ) {
char name [ IF_NAMESIZE ] , * ret ;
int32_t ifindex ;
memcpy ( & ifindex , RTA_DATA ( attrs ) , 4 ) ;
ret = if_indextoname ( ifindex , name ) ;
if ( ret )
printf ( " dev %s " , ret ) ;
else
printf ( " dev unknown/%d " , ifindex ) ;
}
attrs = RTA_NEXT ( attrs , len ) ;
}
printf ( " \n " ) ;
}
static void print_addrs ( struct nlmsghdr * nh , int pm_family , int total_len )
{
struct rtattr * attrs ;
for ( ; NLMSG_OK ( nh , total_len ) ; nh = NLMSG_NEXT ( nh , total_len ) ) {
int len = nh - > nlmsg_len ;
if ( nh - > nlmsg_type = = NLMSG_DONE )
break ;
if ( nh - > nlmsg_type = = NLMSG_ERROR )
nl_error ( nh ) ;
if ( nh - > nlmsg_type ! = pm_family )
continue ;
len - = NLMSG_LENGTH ( GENL_HDRLEN ) ;
attrs = ( struct rtattr * ) ( ( char * ) NLMSG_DATA ( nh ) +
GENL_HDRLEN ) ;
while ( RTA_OK ( attrs , len ) ) {
if ( attrs - > rta_type = =
( MPTCP_PM_ATTR_ADDR | NLA_F_NESTED ) )
print_addr ( ( void * ) RTA_DATA ( attrs ) ,
attrs - > rta_len ) ;
attrs = RTA_NEXT ( attrs , len ) ;
}
}
}
int get_addr ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
struct rtattr * rta , * nest ;
struct nlmsghdr * nh ;
int nest_start ;
u_int8_t id ;
int off = 0 ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_GET_ADDR ,
MPTCP_PM_VER ) ;
/* the only argument is the address id */
if ( argc ! = 3 )
syntax ( argv ) ;
id = atoi ( argv [ 2 ] ) ;
nest_start = off ;
nest = ( void * ) ( data + off ) ;
nest - > rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR ;
nest - > rta_len = RTA_LENGTH ( 0 ) ;
off + = NLMSG_ALIGN ( nest - > rta_len ) ;
/* build a dummy addr with only the ID set */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ID ;
rta - > rta_len = RTA_LENGTH ( 1 ) ;
memcpy ( RTA_DATA ( rta ) , & id , 1 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
nest - > rta_len = off - nest_start ;
print_addrs ( nh , pm_family , do_nl_req ( fd , nh , off , sizeof ( data ) ) ) ;
return 0 ;
}
int dump_addrs ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
pid_t pid = getpid ( ) ;
struct nlmsghdr * nh ;
int off = 0 ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_GET_ADDR ,
MPTCP_PM_VER ) ;
nh - > nlmsg_flags | = NLM_F_DUMP ;
nh - > nlmsg_seq = 1 ;
nh - > nlmsg_pid = pid ;
nh - > nlmsg_len = off ;
print_addrs ( nh , pm_family , do_nl_req ( fd , nh , off , sizeof ( data ) ) ) ;
return 0 ;
}
int flush_addrs ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
struct nlmsghdr * nh ;
int off = 0 ;
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_FLUSH_ADDRS ,
MPTCP_PM_VER ) ;
do_nl_req ( fd , nh , off , 0 ) ;
return 0 ;
}
static void print_limits ( struct nlmsghdr * nh , int pm_family , int total_len )
{
struct rtattr * attrs ;
uint32_t max ;
for ( ; NLMSG_OK ( nh , total_len ) ; nh = NLMSG_NEXT ( nh , total_len ) ) {
int len = nh - > nlmsg_len ;
if ( nh - > nlmsg_type = = NLMSG_DONE )
break ;
if ( nh - > nlmsg_type = = NLMSG_ERROR )
nl_error ( nh ) ;
if ( nh - > nlmsg_type ! = pm_family )
continue ;
len - = NLMSG_LENGTH ( GENL_HDRLEN ) ;
attrs = ( struct rtattr * ) ( ( char * ) NLMSG_DATA ( nh ) +
GENL_HDRLEN ) ;
while ( RTA_OK ( attrs , len ) ) {
int type = attrs - > rta_type ;
if ( type ! = MPTCP_PM_ATTR_RCV_ADD_ADDRS & &
type ! = MPTCP_PM_ATTR_SUBFLOWS )
goto next ;
memcpy ( & max , RTA_DATA ( attrs ) , 4 ) ;
printf ( " %s %u \n " , type = = MPTCP_PM_ATTR_SUBFLOWS ?
" subflows " : " accept " , max ) ;
next :
attrs = RTA_NEXT ( attrs , len ) ;
}
}
}
int get_set_limits ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
uint32_t rcv_addr = 0 , subflows = 0 ;
int cmd , len = sizeof ( data ) ;
struct nlmsghdr * nh ;
int off = 0 ;
/* limit */
if ( argc = = 4 ) {
rcv_addr = atoi ( argv [ 2 ] ) ;
subflows = atoi ( argv [ 3 ] ) ;
cmd = MPTCP_PM_CMD_SET_LIMITS ;
} else {
cmd = MPTCP_PM_CMD_GET_LIMITS ;
}
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , cmd , MPTCP_PM_VER ) ;
/* limit */
if ( cmd = = MPTCP_PM_CMD_SET_LIMITS ) {
struct rtattr * rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ATTR_RCV_ADD_ADDRS ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & rcv_addr , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ATTR_SUBFLOWS ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & subflows , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
/* do not expect a reply */
len = 0 ;
}
len = do_nl_req ( fd , nh , off , len ) ;
if ( cmd = = MPTCP_PM_CMD_GET_LIMITS )
print_limits ( nh , pm_family , len ) ;
return 0 ;
}
2021-01-08 16:48:00 -08:00
int set_flags ( int fd , int pm_family , int argc , char * argv [ ] )
{
char data [ NLMSG_ALIGN ( sizeof ( struct nlmsghdr ) ) +
NLMSG_ALIGN ( sizeof ( struct genlmsghdr ) ) +
1024 ] ;
struct rtattr * rta , * nest ;
struct nlmsghdr * nh ;
u_int32_t flags = 0 ;
u_int16_t family ;
int nest_start ;
2022-02-04 16:03:35 -08:00
int use_id = 0 ;
u_int8_t id ;
2021-01-08 16:48:00 -08:00
int off = 0 ;
2022-02-04 16:03:35 -08:00
int arg = 2 ;
2021-01-08 16:48:00 -08:00
memset ( data , 0 , sizeof ( data ) ) ;
nh = ( void * ) data ;
off = init_genl_req ( data , pm_family , MPTCP_PM_CMD_SET_FLAGS ,
MPTCP_PM_VER ) ;
if ( argc < 3 )
syntax ( argv ) ;
nest_start = off ;
nest = ( void * ) ( data + off ) ;
nest - > rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR ;
nest - > rta_len = RTA_LENGTH ( 0 ) ;
off + = NLMSG_ALIGN ( nest - > rta_len ) ;
2022-02-04 16:03:35 -08:00
if ( ! strcmp ( argv [ arg ] , " id " ) ) {
if ( + + arg > = argc )
error ( 1 , 0 , " missing id value " ) ;
use_id = 1 ;
id = atoi ( argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ID ;
rta - > rta_len = RTA_LENGTH ( 1 ) ;
memcpy ( RTA_DATA ( rta ) , & id , 1 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
2021-01-08 16:48:00 -08:00
} else {
2022-02-04 16:03:35 -08:00
/* addr data */
rta = ( void * ) ( data + off ) ;
if ( inet_pton ( AF_INET , argv [ arg ] , RTA_DATA ( rta ) ) ) {
family = AF_INET ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR4 ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
} else if ( inet_pton ( AF_INET6 , argv [ arg ] , RTA_DATA ( rta ) ) ) {
family = AF_INET6 ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_ADDR6 ;
rta - > rta_len = RTA_LENGTH ( 16 ) ;
} else {
error ( 1 , errno , " can't parse ip %s " , argv [ arg ] ) ;
}
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
/* family */
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_FAMILY ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & family , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
2021-01-08 16:48:00 -08:00
}
2022-02-04 16:03:35 -08:00
if ( + + arg > = argc )
error ( 1 , 0 , " missing flags keyword " ) ;
2021-01-08 16:48:00 -08:00
2022-02-04 16:03:35 -08:00
for ( ; arg < argc ; arg + + ) {
2021-01-08 16:48:00 -08:00
if ( ! strcmp ( argv [ arg ] , " flags " ) ) {
char * tok , * str ;
/* flags */
if ( + + arg > = argc )
error ( 1 , 0 , " missing flags value " ) ;
for ( str = argv [ arg ] ; ( tok = strtok ( str , " , " ) ) ;
str = NULL ) {
if ( ! strcmp ( tok , " backup " ) )
flags | = MPTCP_PM_ADDR_FLAG_BACKUP ;
2022-02-02 17:03:42 -08:00
else if ( ! strcmp ( tok , " fullmesh " ) )
flags | = MPTCP_PM_ADDR_FLAG_FULLMESH ;
else if ( strcmp ( tok , " nobackup " ) & &
strcmp ( tok , " nofullmesh " ) )
2021-01-08 16:48:00 -08:00
error ( 1 , errno ,
" unknown flag %s " , argv [ arg ] ) ;
}
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_FLAGS ;
rta - > rta_len = RTA_LENGTH ( 4 ) ;
memcpy ( RTA_DATA ( rta ) , & flags , 4 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
2022-02-04 16:03:30 -08:00
} else if ( ! strcmp ( argv [ arg ] , " port " ) ) {
u_int16_t port ;
2022-02-04 16:03:35 -08:00
if ( use_id )
error ( 1 , 0 , " port can't be used with id " ) ;
2022-02-04 16:03:30 -08:00
if ( + + arg > = argc )
error ( 1 , 0 , " missing port value " ) ;
port = atoi ( argv [ arg ] ) ;
rta = ( void * ) ( data + off ) ;
rta - > rta_type = MPTCP_PM_ADDR_ATTR_PORT ;
rta - > rta_len = RTA_LENGTH ( 2 ) ;
memcpy ( RTA_DATA ( rta ) , & port , 2 ) ;
off + = NLMSG_ALIGN ( rta - > rta_len ) ;
2021-01-08 16:48:00 -08:00
} else {
error ( 1 , 0 , " unknown keyword %s " , argv [ arg ] ) ;
}
}
nest - > rta_len = off - nest_start ;
do_nl_req ( fd , nh , off , 0 ) ;
return 0 ;
}
2020-03-27 14:48:52 -07:00
int main ( int argc , char * argv [ ] )
{
int fd , pm_family ;
if ( argc < 2 )
syntax ( argv ) ;
fd = socket ( AF_NETLINK , SOCK_RAW , NETLINK_GENERIC ) ;
if ( fd = = - 1 )
error ( 1 , errno , " socket netlink " ) ;
pm_family = resolve_mptcp_pm_netlink ( fd ) ;
if ( ! strcmp ( argv [ 1 ] , " add " ) )
return add_addr ( fd , pm_family , argc , argv ) ;
2022-05-03 19:38:53 -07:00
else if ( ! strcmp ( argv [ 1 ] , " ann " ) )
return announce_addr ( fd , pm_family , argc , argv ) ;
2022-05-03 19:38:55 -07:00
else if ( ! strcmp ( argv [ 1 ] , " rem " ) )
return remove_addr ( fd , pm_family , argc , argv ) ;
2022-05-03 19:38:57 -07:00
else if ( ! strcmp ( argv [ 1 ] , " csf " ) )
return csf ( fd , pm_family , argc , argv ) ;
2022-05-03 19:38:58 -07:00
else if ( ! strcmp ( argv [ 1 ] , " dsf " ) )
return dsf ( fd , pm_family , argc , argv ) ;
2020-03-27 14:48:52 -07:00
else if ( ! strcmp ( argv [ 1 ] , " del " ) )
return del_addr ( fd , pm_family , argc , argv ) ;
else if ( ! strcmp ( argv [ 1 ] , " flush " ) )
return flush_addrs ( fd , pm_family , argc , argv ) ;
else if ( ! strcmp ( argv [ 1 ] , " get " ) )
return get_addr ( fd , pm_family , argc , argv ) ;
else if ( ! strcmp ( argv [ 1 ] , " dump " ) )
return dump_addrs ( fd , pm_family , argc , argv ) ;
else if ( ! strcmp ( argv [ 1 ] , " limits " ) )
return get_set_limits ( fd , pm_family , argc , argv ) ;
2021-01-08 16:48:00 -08:00
else if ( ! strcmp ( argv [ 1 ] , " set " ) )
return set_flags ( fd , pm_family , argc , argv ) ;
2020-03-27 14:48:52 -07:00
fprintf ( stderr , " unknown sub-command: %s " , argv [ 1 ] ) ;
syntax ( argv ) ;
return 0 ;
}