@@ -1079,41 +1079,49 @@ nc_session_free(struct nc_session *session, void (*data_free)(void *))
10791079 free (session );
10801080}
10811081
1082- static void
1083- add_cpblt (const char * capab , char * * * cpblts , int * size , int * count )
1082+ /**
1083+ * @brief Add a capability into an array.
1084+ *
1085+ * @param[in] capab Capability to add.
1086+ * @param[in,out] cpblts Array of capabilities to add to, terminated with NULL.
1087+ * @param[in,out] count Count of @p cpblts.
1088+ * @return 0 on success;
1089+ * @return -1 on error.
1090+ */
1091+ static int
1092+ nc_add_cpblt (const char * capab , char * * * cpblts , uint32_t * count )
10841093{
1085- size_t len ;
1086- int i ;
1094+ uint32_t i , len ;
10871095 char * p ;
10881096
1089- if (capab ) {
1090- /* check if already present */
1091- p = strchr (capab , '?' );
1092- if (p ) {
1093- len = p - capab ;
1094- } else {
1095- len = strlen (capab );
1096- }
1097- for (i = 0 ; i < * count ; i ++ ) {
1098- if (!strncmp ((* cpblts )[i ], capab , len ) && (((* cpblts )[i ][len ] == '\0' ) || ((* cpblts )[i ][len ] == '?' ))) {
1099- /* already present, do not duplicate it */
1100- return ;
1101- }
1097+ /* check if already present */
1098+ p = strchr (capab , '?' );
1099+ if (p ) {
1100+ len = p - capab ;
1101+ } else {
1102+ len = strlen (capab );
1103+ }
1104+ for (i = 0 ; i < * count ; i ++ ) {
1105+ if (!strncmp ((* cpblts )[i ], capab , len ) && (((* cpblts )[i ][len ] == '\0' ) || ((* cpblts )[i ][len ] == '?' ))) {
1106+ /* already present, do not duplicate it */
1107+ return 0 ;
11021108 }
11031109 }
11041110
11051111 /* add another capability */
1106- if (* count == * size ) {
1107- * size += 5 ;
1108- * cpblts = nc_realloc (* cpblts , * size * sizeof * * cpblts );
1109- if (!(* cpblts )) {
1110- ERRMEM ;
1111- return ;
1112- }
1112+ * cpblts = nc_realloc (* cpblts , (* count + 2 ) * sizeof * * cpblts );
1113+ if (!(* cpblts )) {
1114+ ERRMEM ;
1115+ return -1 ;
11131116 }
11141117
1115- (* cpblts )[* count ] = capab ? strdup (capab ) : NULL ;
1118+ (* cpblts )[* count ] = strdup (capab );
11161119 ++ (* count );
1120+
1121+ /* terminating NULL */
1122+ (* cpblts )[* count ] = NULL ;
1123+
1124+ return 0 ;
11171125}
11181126
11191127/**
@@ -1122,63 +1130,63 @@ add_cpblt(const char *capab, char ***cpblts, int *size, int *count)
11221130 * @param[in] ctx libyang context.
11231131 * @param[in] version YANG version of the schemas to be included in result.
11241132 * @param[in] config_locked Whether the configuration lock is already held or should be acquired.
1125- * @return Array of capabilities, NULL on error.
1133+ * @return Array of capabilities terminated with NULL , NULL on error.
11261134 */
11271135static char * *
11281136_nc_server_get_cpblts_version (const struct ly_ctx * ctx , LYS_VERSION version , int config_locked )
11291137{
11301138 char * * cpblts ;
11311139 const struct lys_module * mod ;
11321140 const char * feat ;
1133- int size = 10 , count , features_count = 0 , dev_count = 0 , str_len , len ;
1134- uint32_t u ;
1141+ int features_count = 0 , dev_count = 0 , str_len , len ;
1142+ uint32_t i , count ;
11351143 LY_ARRAY_COUNT_TYPE v ;
11361144 char * yl_content_id ;
1137- uint32_t wd_also_supported ;
1138- uint32_t wd_basic_mode ;
1145+ uint32_t wd_also_supported , wd_basic_mode ;
11391146
11401147#define NC_CPBLT_BUF_LEN 4096
11411148 char str [NC_CPBLT_BUF_LEN ];
11421149
11431150 NC_CHECK_ARG_RET (NULL , ctx , NULL );
11441151
1145- cpblts = malloc (size * sizeof * cpblts );
1152+ cpblts = malloc (3 * sizeof * cpblts );
11461153 NC_CHECK_ERRMEM_GOTO (!cpblts , , error );
11471154 cpblts [0 ] = strdup ("urn:ietf:params:netconf:base:1.0" );
11481155 cpblts [1 ] = strdup ("urn:ietf:params:netconf:base:1.1" );
1156+ cpblts [2 ] = NULL ;
11491157 count = 2 ;
11501158
11511159 mod = ly_ctx_get_module_implemented (ctx , "ietf-netconf" );
11521160 if (mod ) {
11531161 if (lys_feature_value (mod , "writable-running" ) == LY_SUCCESS ) {
1154- add_cpblt ( "urn:ietf:params:netconf:capability:writable-running:1.0" , & cpblts , & size , & count );
1162+ NC_CHECK_GOTO ( nc_add_cpblt ( "urn:ietf:params:netconf:capability:writable-running:1.0" , & cpblts , & count ), error );
11551163 }
11561164 if (lys_feature_value (mod , "candidate" ) == LY_SUCCESS ) {
1157- add_cpblt ( "urn:ietf:params:netconf:capability:candidate:1.0" , & cpblts , & size , & count );
1165+ NC_CHECK_GOTO ( nc_add_cpblt ( "urn:ietf:params:netconf:capability:candidate:1.0" , & cpblts , & count ), error );
11581166 if (lys_feature_value (mod , "confirmed-commit" ) == LY_SUCCESS ) {
1159- add_cpblt ( "urn:ietf:params:netconf:capability:confirmed-commit:1.1" , & cpblts , & size , & count );
1167+ NC_CHECK_GOTO ( nc_add_cpblt ( "urn:ietf:params:netconf:capability:confirmed-commit:1.1" , & cpblts , & count ), error );
11601168 }
11611169 }
11621170 if (lys_feature_value (mod , "rollback-on-error" ) == LY_SUCCESS ) {
1163- add_cpblt ( "urn:ietf:params:netconf:capability:rollback-on-error:1.0" , & cpblts , & size , & count );
1171+ NC_CHECK_GOTO ( nc_add_cpblt ( "urn:ietf:params:netconf:capability:rollback-on-error:1.0" , & cpblts , & count ), error );
11641172 }
11651173 if (lys_feature_value (mod , "validate" ) == LY_SUCCESS ) {
1166- add_cpblt ( "urn:ietf:params:netconf:capability:validate:1.1" , & cpblts , & size , & count );
1174+ NC_CHECK_GOTO ( nc_add_cpblt ( "urn:ietf:params:netconf:capability:validate:1.1" , & cpblts , & count ), error );
11671175 }
11681176 if (lys_feature_value (mod , "startup" ) == LY_SUCCESS ) {
1169- add_cpblt ( "urn:ietf:params:netconf:capability:startup:1.0" , & cpblts , & size , & count );
1177+ NC_CHECK_GOTO ( nc_add_cpblt ( "urn:ietf:params:netconf:capability:startup:1.0" , & cpblts , & count ), error );
11701178 }
11711179
11721180 /* The URL capability must be set manually using nc_server_set_capability()
11731181 * because of the need for supported protocols to be included.
11741182 * https://tools.ietf.org/html/rfc6241#section-8.8.3
11751183 */
11761184 // if (lys_feature_value(mod, "url") == LY_SUCCESS) {
1177- // add_cpblt( "urn:ietf:params:netconf:capability:url:1.0", &cpblts, &size, &count );
1185+ // NC_CHECK_GOTO(nc_add_cpblt( "urn:ietf:params:netconf:capability:url:1.0", &cpblts, &count), error );
11781186 // }
11791187
11801188 if (lys_feature_value (mod , "xpath" ) == LY_SUCCESS ) {
1181- add_cpblt ( "urn:ietf:params:netconf:capability:xpath:1.0" , & cpblts , & size , & count );
1189+ NC_CHECK_GOTO ( nc_add_cpblt ( "urn:ietf:params:netconf:capability:xpath:1.0" , & cpblts , & count ), error );
11821190 }
11831191 }
11841192
@@ -1227,19 +1235,19 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
12271235 }
12281236 str [strlen (str ) - 1 ] = '\0' ;
12291237
1230- add_cpblt ( str , & cpblts , & size , & count );
1238+ NC_CHECK_GOTO ( nc_add_cpblt ( str , & cpblts , & count ), error );
12311239 }
12321240 }
12331241 }
12341242
12351243 /* other capabilities */
1236- for (u = 0 ; u < server_opts .capabilities_count ; u ++ ) {
1237- add_cpblt ( server_opts .capabilities [u ], & cpblts , & size , & count );
1244+ for (i = 0 ; i < server_opts .capabilities_count ; i ++ ) {
1245+ NC_CHECK_GOTO ( nc_add_cpblt ( server_opts .capabilities [i ], & cpblts , & count ), error );
12381246 }
12391247
12401248 /* models */
1241- u = 0 ;
1242- while ((mod = ly_ctx_get_module_iter (ctx , & u ))) {
1249+ i = 0 ;
1250+ while ((mod = ly_ctx_get_module_iter (ctx , & i ))) {
12431251 if (nc_server_is_mod_ignored (mod -> name , config_locked )) {
12441252 /* ignored, not part of the cababilities */
12451253 continue ;
@@ -1265,12 +1273,12 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
12651273 /* new one (capab defined in RFC 8526 section 2) */
12661274 sprintf (str , "urn:ietf:params:netconf:capability:yang-library:1.1?revision=%s&content-id=%s" ,
12671275 mod -> revision , yl_content_id );
1268- add_cpblt ( str , & cpblts , & size , & count );
1276+ NC_CHECK_GOTO ( nc_add_cpblt ( str , & cpblts , & count ), error );
12691277 } else {
12701278 /* old one (capab defined in RFC 7950 section 5.6.4) */
12711279 sprintf (str , "urn:ietf:params:netconf:capability:yang-library:1.0?revision=%s&module-set-id=%s" ,
12721280 mod -> revision , yl_content_id );
1273- add_cpblt ( str , & cpblts , & size , & count );
1281+ NC_CHECK_GOTO ( nc_add_cpblt ( str , & cpblts , & count ), error );
12741282 }
12751283 free (yl_content_id );
12761284 continue ;
@@ -1325,23 +1333,25 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
13251333 }
13261334 }
13271335
1328- add_cpblt ( str , & cpblts , & size , & count );
1336+ NC_CHECK_GOTO ( nc_add_cpblt ( str , & cpblts , & count ), error );
13291337 }
13301338
13311339 /* HELLO UNLOCK */
13321340 nc_rwlock_unlock (& server_opts .hello_lock , __func__ );
13331341
1334- /* ending NULL capability */
1335- add_cpblt (NULL , & cpblts , & size , & count );
1336-
13371342 return cpblts ;
13381343
13391344unlock_error :
13401345 /* HELLO UNLOCK */
13411346 nc_rwlock_unlock (& server_opts .hello_lock , __func__ );
13421347
13431348error :
1344- free (cpblts );
1349+ if (cpblts ) {
1350+ for (i = 0 ; cpblts [i ]; ++ i ) {
1351+ free (cpblts [i ]);
1352+ }
1353+ free (cpblts );
1354+ }
13451355 return NULL ;
13461356}
13471357
@@ -1414,6 +1424,44 @@ parse_cpblts(struct lyd_node *capabilities, char ***list)
14141424 return ver ;
14151425}
14161426
1427+ /**
1428+ * @brief Get client-side capabilities.
1429+ *
1430+ * @return Array of capabilities terminated with NULL, NULL on error.
1431+ */
1432+ static char * *
1433+ nc_client_get_cpblts (void )
1434+ {
1435+ char * * cpblts = NULL ;
1436+ uint32_t i , count ;
1437+
1438+ cpblts = malloc (3 * sizeof * cpblts );
1439+ NC_CHECK_ERRMEM_GOTO (!cpblts , , error );
1440+
1441+ cpblts [0 ] = strdup ("urn:ietf:params:netconf:base:1.0" );
1442+ NC_CHECK_ERRMEM_GOTO (!cpblts [0 ], , error );
1443+ cpblts [1 ] = strdup ("urn:ietf:params:netconf:base:1.1" );
1444+ NC_CHECK_ERRMEM_GOTO (!cpblts [1 ], , error );
1445+ cpblts [2 ] = NULL ;
1446+ count = 3 ;
1447+
1448+ /* custom capabilities */
1449+ for (i = 0 ; i < client_opts .capabilities_count ; ++ i ) {
1450+ NC_CHECK_GOTO (nc_add_cpblt (client_opts .capabilities [i ], & cpblts , & count ), error );
1451+ }
1452+
1453+ return cpblts ;
1454+
1455+ error :
1456+ if (cpblts ) {
1457+ for (i = 0 ; cpblts [i ]; ++ i ) {
1458+ free (cpblts [i ]);
1459+ }
1460+ free (cpblts );
1461+ }
1462+ return NULL ;
1463+ }
1464+
14171465/**
14181466 * @brief Send NETCONF hello message on a session.
14191467 *
@@ -1431,11 +1479,10 @@ nc_send_hello_io(struct nc_session *session, int config_locked)
14311479
14321480 if (session -> side == NC_CLIENT ) {
14331481 /* client side hello - send only NETCONF base capabilities */
1434- cpblts = malloc (3 * sizeof * cpblts );
1435- NC_CHECK_ERRMEM_RET (!cpblts , NC_MSG_ERROR );
1436- cpblts [0 ] = strdup ("urn:ietf:params:netconf:base:1.0" );
1437- cpblts [1 ] = strdup ("urn:ietf:params:netconf:base:1.1" );
1438- cpblts [2 ] = NULL ;
1482+ cpblts = nc_client_get_cpblts ();
1483+ if (!cpblts ) {
1484+ return NC_MSG_ERROR ;
1485+ }
14391486
14401487 timeout_io = NC_CLIENT_HELLO_TIMEOUT * 1000 ;
14411488 sid = NULL ;
0 commit comments