Browse code

Merge 78cea07e7858616942981eab4a0238796689fe9c into 81265e41b52cfda9a284233c93683522a98f0a64

Kristiyan Peychev authored on 18/05/2022 11:24:50 • GitHub committed on 18/05/2022 11:24:50
Showing 11 changed files
... ...
@@ -50,7 +50,6 @@
50 50
 
51 51
 #include "ipsec.h"
52 52
 #include "spi_gen.h"
53
-#include "port_gen.h"
54 53
 #include "cmd.h"
55 54
 #include "sec_agree.h"
56 55
 
... ...
@@ -351,57 +350,26 @@ static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m, ipse
351 350
     s->ik.len = ik.len;
352 351
 
353 352
     // Generate SPI
354
-    if((s->spi_pc = acquire_spi()) == 0) {
355
-        LM_ERR("Error generating client SPI for IPSEC tunnel creation\n");
356
-        shm_free(s->ck.s);
357
-        s->ck.s = NULL; s->ck.len = 0;
358
-        shm_free(s->ik.s);
359
-        s->ik.s = NULL; s->ik.len = 0;
360
-        return -1;
353
+    if(s_old) {
354
+        if(s_old->spi_pc && s_old->spi_ps && s_old->port_pc && s_old->port_ps) {
355
+            LM_INFO("Reusing IPSEC tunnel\n");
356
+            s->spi_pc = s_old->spi_pc;
357
+            s->spi_ps = s_old->spi_ps;
358
+            s->port_pc = s_old->port_pc;
359
+            s->port_ps = s_old->port_ps;
360
+            return 0;
361
+        }
361 362
     }
362 363
 
363
-    if((s->spi_ps = acquire_spi()) == 0) {
364
-        LM_ERR("Error generating server SPI for IPSEC tunnel creation\n");
364
+    if(acquire_spi(&s->spi_pc, &s->spi_ps, &s->port_pc, &s->port_ps) == 0) {
365
+        LM_ERR("Error generating client SPI for IPSEC tunnel creation\n");
365 366
         shm_free(s->ck.s);
366 367
         s->ck.s = NULL; s->ck.len = 0;
367 368
         shm_free(s->ik.s);
368 369
         s->ik.s = NULL; s->ik.len = 0;
369
-
370
-		release_spi(s->spi_pc);
371 370
         return -1;
372 371
     }
373 372
 
374
-    if((s->port_pc = acquire_cport()) == 0){
375
-        LM_ERR("No free client port for IPSEC tunnel creation\n");
376
-		shm_free(s->ck.s);
377
-		s->ck.s = NULL; s->ck.len = 0;
378
-		shm_free(s->ik.s);
379
-		s->ik.s = NULL; s->ik.len = 0;
380
-
381
-		release_spi(s->spi_pc);
382
-		release_spi(s->spi_ps);
383
-        return -1;
384
-    }
385
-
386
-	// use the same P-CSCF server port if it is present
387
-	if(s_old){
388
-		s->port_ps = s_old->port_ps;
389
-	}else{
390
-		if((s->port_ps = acquire_sport()) == 0){
391
-			LM_ERR("No free server port for IPSEC tunnel creation\n");
392
-			shm_free(s->ck.s);
393
-			s->ck.s = NULL; s->ck.len = 0;
394
-			shm_free(s->ik.s);
395
-			s->ik.s = NULL; s->ik.len = 0;
396
-
397
-			release_cport(s->port_pc);
398
-
399
-			release_spi(s->spi_pc);
400
-			release_spi(s->spi_ps);
401
-			return -1;
402
-		}
403
-	}
404
-
405 373
 	return 0;
406 374
 }
407 375
 
... ...
@@ -508,12 +476,7 @@ static int destroy_ipsec_tunnel(str remote_addr, ipsec_t* s, unsigned short rece
508 476
     remove_policy(sock, remote_addr, ipsec_addr, s->port_us, s->port_pc, s->spi_pc, ip_addr.af, IPSEC_POLICY_DIRECTION_IN);
509 477
 
510 478
     // Release SPIs
511
-    release_spi(s->spi_pc);
512
-    release_spi(s->spi_ps);
513
-
514
-    // Release the client and the server ports
515
-    release_cport(s->port_pc);
516
-    release_sport(s->port_ps);
479
+    release_spi(s->spi_pc, s->spi_ps, s->port_pc, s->port_ps);
517 480
 
518 481
     close_mnl_socket(sock);
519 482
     return 0;
... ...
@@ -692,74 +655,69 @@ int ipsec_create(struct sip_msg* m, udomain_t* d, int _cflags)
692 655
 
693 656
     struct sip_msg* req = t->uas.request;
694 657
 
658
+    // Parse security parameters from the REGISTER request and get some data for the new tunnels
659
+    security_t* req_sec_params = cscf_get_security(req);
660
+    ipsec_t* s;
661
+    ipsec_t* old_s = NULL;
662
+
695 663
     // Update contacts only for initial registration, for re-registration the existing contacts shouldn't be updated.
696 664
     if(ci.via_port == SIP_PORT){
697 665
         LM_DBG("Registration for contact with AOR [%.*s], VIA [%d://%.*s:%d], received_host [%d://%.*s:%d]\n",
698 666
                 ci.aor.len, ci.aor.s, ci.via_prot, ci.via_host.len, ci.via_host.s, ci.via_port,
699 667
                 ci.received_proto, ci.received_host.len, ci.received_host.s, ci.received_port);
700 668
 
701
-        ipsec_t* s = pcontact->security_temp->data.ipsec;
669
+        if(req_sec_params == NULL)
670
+            s = pcontact->security_temp->data.ipsec;
671
+        else
672
+            s = req_sec_params->data.ipsec;
673
+    }else{
674
+        LM_DBG("RE-Registration for contact with AOR [%.*s], VIA [%d://%.*s:%d], received_host [%d://%.*s:%d]\n",
675
+                ci.aor.len, ci.aor.s, ci.via_prot, ci.via_host.len, ci.via_host.s, ci.via_port,
676
+                ci.received_proto, ci.received_host.len, ci.received_host.s, ci.received_port);
702 677
 
703
-		// for initial Registration use a new P-CSCF server port
704
-        if(update_contact_ipsec_params(s, m, NULL) != 0) {
678
+        if(req_sec_params == NULL) {
679
+            LM_CRIT("No security parameters in REGISTER request\n");
705 680
             goto cleanup;
706 681
         }
707 682
 
708
-        if(create_ipsec_tunnel(&req->rcv.src_ip, s) != 0){
709
-            goto cleanup;
710
-        }
683
+        s = req_sec_params->data.ipsec;
684
+        old_s = (ipsec_reuse_server_port && pcontact->security_temp) ? pcontact->security_temp->data.ipsec : NULL;
685
+    }
711 686
 
712
-        if (ul.update_pcontact(d, &ci, pcontact) != 0){
713
-            LM_ERR("Error updating contact\n");
714
-            goto cleanup;
715
-        }
687
+    if(update_contact_ipsec_params(s, m, old_s) != 0) {
688
+        goto cleanup;
689
+    }
716 690
 
691
+    if(create_ipsec_tunnel(&req->rcv.src_ip, s) != 0){
692
+        goto cleanup;
693
+    }
694
+
695
+    if (ul.update_pcontact(d, &ci, pcontact) != 0){
696
+        LM_ERR("Error updating contact\n");
697
+        goto cleanup;
698
+    }
699
+
700
+    if(ci.via_port == SIP_PORT){
717 701
         // Update temp security parameters
718 702
         if(ul.update_temp_security(d, pcontact->security_temp->type, pcontact->security_temp, pcontact) != 0){
719 703
             LM_ERR("Error updating temp security\n");
720 704
         }
705
+    }
721 706
 
722
-        if(add_supported_secagree_header(m) != 0) {
723
-            goto cleanup;
724
-        }
725 707
 
726
-        if(add_security_server_header(m, s) != 0) {
727
-            goto cleanup;
728
-        }
708
+    if(add_supported_secagree_header(m) != 0) {
709
+        goto cleanup;
710
+    }
729 711
 
712
+    if(add_security_server_header(m, s) != 0) {
713
+        goto cleanup;
714
+    }
715
+
716
+    if(ci.via_port == SIP_PORT){
730 717
         if(ul.register_ulcb(pcontact, PCSCF_CONTACT_EXPIRE|PCSCF_CONTACT_DELETE, ipsec_on_expire, (void*)&pcontact->received_port) != 1) {
731 718
             LM_ERR("Error subscribing for contact\n");
732 719
             goto cleanup;
733 720
         }
734
-    }else{
735
-        LM_DBG("RE-Registration for contact with AOR [%.*s], VIA [%d://%.*s:%d], received_host [%d://%.*s:%d]\n",
736
-                ci.aor.len, ci.aor.s, ci.via_prot, ci.via_host.len, ci.via_host.s, ci.via_port,
737
-                ci.received_proto, ci.received_host.len, ci.received_host.s, ci.received_port);
738
-        
739
-        security_t* req_sec_params = NULL;
740
-
741
-        // Parse security parameters from the REGISTER request and get some data for the new tunnels
742
-        if((req_sec_params = cscf_get_security(req)) == NULL) {
743
-            LM_CRIT("No security parameters in REGISTER request\n");
744
-            goto cleanup;
745
-        }
746
-
747
-		// for Re-Registration use the same P-CSCF server port if 'ipsec reuse server port' is enabled
748
-        if(update_contact_ipsec_params(req_sec_params->data.ipsec, m, ipsec_reuse_server_port ? pcontact->security_temp->data.ipsec : NULL) != 0) {
749
-            goto cleanup;
750
-        }
751
-
752
-        if(create_ipsec_tunnel(&req->rcv.src_ip, req_sec_params->data.ipsec) != 0){
753
-            goto cleanup;
754
-        }
755
-
756
-        if(add_supported_secagree_header(m) != 0) {
757
-            goto cleanup;
758
-        }
759
-
760
-        if(add_security_server_header(m, req_sec_params->data.ipsec) != 0) {
761
-            goto cleanup;
762
-        }
763 721
     }
764 722
 
765 723
     ret = IPSEC_CMD_SUCCESS;    // all good, set ret to SUCCESS, and exit
... ...
@@ -1004,10 +962,9 @@ int ipsec_reconfig()
1004 962
 		return 0;
1005 963
 	}
1006 964
 
1007
-	clean_spi_list();
1008
-	clean_port_lists();
1009
-
1010
-	LM_DBG("Clean all ipsec tunnels\n");
965
+	if(clean_spi_list() != 0) {
966
+		return 1;
967
+	}
1011 968
 
1012 969
 	return ipsec_cleanall();
1013 970
 }
... ...
@@ -82,7 +82,7 @@ modparam("ims_ipsec_pcscf", "ipsec_listen_addr6", "")
82 82
     <section>
83 83
       <title><varname>ipsec_client_port</varname> (int)</title>
84 84
 
85
-      <para>Start port number which will be bound for incoming (server) IPSec traffic.</para>
85
+      <para>Port number which will be bound for incoming (server) IPSec traffic.</para>
86 86
 
87 87
       <para><emphasis>Default value is 5062.</emphasis></para>
88 88
 
... ...
@@ -100,7 +100,7 @@ modparam("ims_ipsec_pcscf", "ipsec_client_port", 5062)
100 100
     <section>
101 101
       <title><varname>ipsec_server_port</varname> (int)</title>
102 102
 
103
-      <para>Start port number which will be bound for incoming (server) IPSec traffic.</para>
103
+      <para>Port number which will be bound for incoming (server) IPSec traffic.</para>
104 104
 
105 105
       <para><emphasis>Default value is 5063.</emphasis></para>
106 106
 
... ...
@@ -118,9 +118,7 @@ modparam("ims_ipsec_pcscf", "ipsec_server_port", 5063)
118 118
     <section>
119 119
       <title><varname>ipsec_max_connections</varname> (int)</title>
120 120
 
121
-      <para>Maximum IPSec connections for the process. E.g. if ipsec_client_port=5100, ipsec_server_port=6100 and
122
-      ipsec_max_connections=10, all client ports between 5100 and 5109 and all server ports between 6100 and 6109
123
-      will be used for maximum to 10 IPSec connections.</para>
121
+      <para>Maximum simultanious IPSec connections</para>
124 122
 
125 123
       <para><emphasis>Default value is 2.</emphasis></para>
126 124
 
... ...
@@ -138,11 +136,9 @@ modparam("ims_ipsec_pcscf", "ipsec_max_connections", 10)
138 136
     <section>
139 137
       <title><varname>ipsec_reuse_server_port</varname> (int)</title>
140 138
 
141
-      <para>Reuse (1) or not (0) the P-CSCF Server port for Re-registration for one UA.
142
-      When set to 0 - During Re-registration P-CSCF will distribute new P-CSCF client and
143
-      P-CSCF server ports.
144
-      When set to 1 - During Re-registration P-CSCF will reuse the old P-CSCF server port and
145
-      will distribute a new P-CSCF client port.</para>
139
+      <para>Reuse (1) or not (0) the P-CSCF IPSec information for Re-registration for one UA.
140
+      When set to 0 - During Re-registration P-CSCF will create new IPSec tunnels.
141
+      When set to 1 - During Re-registration P-CSCF will reuse the old IPSec tunnels.</para>
146 142
 
147 143
       <para><emphasis>Default value is 1.</emphasis></para>
148 144
 
... ...
@@ -192,6 +188,40 @@ modparam("ims_ipsec_pcscf", "ipsec_spi_id_start", 100)
192 188
         <programlisting format="linespecific">
193 189
 ...
194 190
 modparam("ims_ipsec_pcscf", "ipsec_spi_id_range", 1000)
191
+...
192
+        </programlisting>
193
+      </example>
194
+    </section>
195
+
196
+    <section>
197
+      <title><varname>ipsec_preferred_alg</varname> (string)</title>
198
+
199
+      <para>A name of an authentication algorithm which the Proxy-CSCF will <emphasis>prefer</emphasis> when creating IPSec tunnels.</para>
200
+      <para><emphasis>Default value is empty string (null) - the last algorithm in the Sec-Agree header will be used.</emphasis></para>
201
+
202
+      <example>
203
+        <title><varname>ipsec_preferred_alg</varname> parameter usage</title>
204
+
205
+        <programlisting format="linespecific">
206
+...
207
+modparam("ims_ipsec_pcscf", "ipsec_preferred_alg", "hmac-sha-1-96")
208
+...
209
+        </programlisting>
210
+      </example>
211
+    </section>
212
+
213
+    <section>
214
+      <title><varname>ipsec_preferred_ealg</varname> (string)</title>
215
+
216
+      <para>A name of an encrytion algorithm which the Proxy-CSCF will <emphasis>prefer</emphasis> when creating IPSec tunnels.</para>
217
+      <para><emphasis>Default value is empty string (null) - the last algorithm in the Sec-Agree header will be used. Note that the possibility of it being the "null" algorithm is not insignificant.</emphasis></para>
218
+
219
+      <example>
220
+        <title><varname>ipsec_preferred_ealg</varname> parameter usage</title>
221
+
222
+        <programlisting format="linespecific">
223
+...
224
+modparam("ims_ipsec_pcscf", "ipsec_preferred_ealg", "aes-cbc")
195 225
 ...
196 226
         </programlisting>
197 227
       </example>
... ...
@@ -28,8 +28,6 @@
28 28
 
29 29
 #include "cmd.h"
30 30
 #include "spi_gen.h"
31
-#include "port_gen.h"
32
-
33 31
 
34 32
 MODULE_VERSION
35 33
 
... ...
@@ -45,6 +43,8 @@ int ipsec_reuse_server_port = 1;
45 43
 int ipsec_max_connections = 2;
46 44
 int spi_id_start = 100;
47 45
 int spi_id_range = 1000;
46
+str ipsec_preferred_alg= STR_NULL;
47
+str ipsec_preferred_ealg= STR_NULL;
48 48
 int xfrm_user_selector = 143956232;
49 49
 
50 50
 ip_addr_t ipsec_listen_ip_addr;
... ...
@@ -92,6 +92,8 @@ static param_export_t params[] = {
92 92
 	{"ipsec_max_connections",	INT_PARAM, &ipsec_max_connections	},
93 93
 	{"ipsec_spi_id_start",		INT_PARAM, &spi_id_start			},
94 94
 	{"ipsec_spi_id_range",		INT_PARAM, &spi_id_range			},
95
+	{"ipsec_preferred_alg",		PARAM_STR, &ipsec_preferred_alg		},
96
+	{"ipsec_preferred_ealg",	PARAM_STR, &ipsec_preferred_ealg	},
95 97
 	{0, 0, 0}
96 98
 };
97 99
 
... ...
@@ -302,16 +304,11 @@ static int mod_init(void) {
302 304
 	}
303 305
 
304 306
 	int res = 0;
305
-	if((res = init_spi_gen(spi_id_start, spi_id_range)) != 0) {
307
+    if((res = init_spi_gen(spi_id_start, spi_id_range, ipsec_server_port, ipsec_client_port, ipsec_max_connections)) != 0) {
306 308
 		LM_ERR("Error initialising spi generator. Error: %d\n", res);
307 309
 		return -1;
308 310
 	}
309 311
 
310
-	if((res = init_port_gen(ipsec_server_port, ipsec_client_port, ipsec_max_connections)) != 0) {
311
-		LM_ERR("Error initialising port generator. Error: %d\n", res);
312
-		return -1;
313
-	}
314
-
315 312
 	init_flag = 1;
316 313
 
317 314
 	return 0;
... ...
@@ -327,9 +324,6 @@ static void mod_destroy(void)
327 324
 		LM_ERR("Error destroying spi generator\n");
328 325
 	}
329 326
 
330
-	if(destroy_port_gen() != 0){
331
-		LM_ERR("Error destroying port generator\n");
332
-	}
333 327
 }
334 328
 
335 329
 static int child_init(int rank)
... ...
@@ -24,7 +24,6 @@
24 24
 
25 25
 #include "ipsec.h"
26 26
 #include "spi_gen.h"
27
-#include "port_gen.h"
28 27
 
29 28
 #include "../../core/dprint.h"
30 29
 #include "../../core/mem/pkg.h"
... ...
@@ -198,27 +197,19 @@ int add_sa(struct mnl_socket* nl_sock, const struct ip_addr *src_addr_param, con
198 197
 
199 198
     // add encription algorithm for this SA
200 199
     l_enc_algo = (struct xfrm_algo *)l_enc_algo_buf;
201
-    // cipher_null, des,  des3_ede, aes
202
-    strcpy(l_enc_algo->alg_name,"cipher_null");
203 200
     if (strncasecmp(r_ealg.s,"aes-cbc",r_ealg.len) == 0) {
204
-        LM_DBG("Creating security associations: AES\n");
205 201
         strcpy(l_enc_algo->alg_name,"aes");
206 202
         l_enc_algo->alg_key_len = ck.len * 4;
207 203
         string_to_key(l_enc_algo->alg_key, ck);
208 204
     }
209 205
     else if (strncasecmp(r_ealg.s,"des-ede3-cbc",r_ealg.len) == 0) {
210
-        LM_DBG("Creating security associations: DES, ck.len=%d\n",ck.len);
211 206
         strcpy(l_enc_algo->alg_name,"des3_ede");
212
-        str ck1;
213
-        ck1.s = pkg_malloc (128);
214
-        strncpy(ck1.s,ck.s,32);
215
-        strncat(ck1.s,ck.s,16);
216
-        ck1.len=32+16;
217
-
218
-        l_enc_algo->alg_key_len = ck1.len * 4;
219
-        string_to_key(l_enc_algo->alg_key, ck1);
220
-
221
-        pkg_free(ck1.s);
207
+        l_enc_algo->alg_key_len = ck.len * 4;
208
+        string_to_key(l_enc_algo->alg_key, ck);
209
+    } else {
210
+        // set default algorithm to null
211
+        strcpy(l_enc_algo->alg_name,"cipher_null");
212
+    	l_enc_algo->alg_key_len = 0;
222 213
     }
223 214
 
224 215
     mnl_attr_put(l_nlh, XFRMA_ALG_CRYPT, sizeof(struct xfrm_algo) + l_enc_algo->alg_key_len, l_enc_algo);
... ...
@@ -814,13 +805,7 @@ static int delete_unused_sa_cb(const struct nlmsghdr *nlh, void *data)
814 805
 
815 806
     // NOTE: Release the Proxy SPIs and Ports only here. Do not release the same SPIs and ports in delete unsused policy callback.
816 807
     // Release SPIs
817
-    release_spi(ipsec.spi_pc);
818
-    release_spi(ipsec.spi_ps);
819
-
820
-    // Release the client and the server ports
821
-    release_cport(ipsec.port_pc);
822
-    release_sport(ipsec.port_ps);
823
-
808
+    release_spi(ipsec.spi_pc, ipsec.spi_ps, ipsec.port_pc, ipsec.port_ps);
824 809
     return MNL_CB_OK;
825 810
 }
826 811
 
827 812
deleted file mode 100644
... ...
@@ -1,227 +0,0 @@
1
-/*
2
- * IMS IPSEC PCSCF module
3
- *
4
- * Copyright (C) 2018 Tsvetomir Dimitrov
5
- * Copyright (C) 2019 Aleksandar Yosifov
6
- *
7
- * This file is part of Kamailio, a free SIP server.
8
- *
9
- * Kamailio is free software; you can redistribute it and/or modify
10
- * it under the terms of the GNU General Public License as published by
11
- * the Free Software Foundation; either version 2 of the License, or
12
- * (at your option) any later version
13
- *
14
- * Kamailio is distributed in the hope that it will be useful,
15
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
- * GNU General Public License for more details.
18
- *
19
- * You should have received a copy of the GNU General Public License
20
- * along with this program; if not, write to the Free Software
21
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
- *
23
- */
24
-
25
-#include "spi_gen.h"
26
-#include "spi_list.h"
27
-#include <pthread.h>
28
-#include "../../core/mem/shm_mem.h"
29
-
30
-typedef struct port_generator{
31
-	pthread_mutex_t	sport_mut;		// server port mutex
32
-	pthread_mutex_t	cport_mut;		// client port mutex
33
-	spi_list_t		used_sports;	// list with used server ports
34
-	spi_list_t		used_cports;	// list with used client ports
35
-	uint32_t		sport_val;		// the last acquired server port
36
-	uint32_t		cport_val;		// the last acquired client port
37
-	uint32_t		min_sport;
38
-	uint32_t		min_cport;
39
-	uint32_t		max_sport;
40
-	uint32_t		max_cport;
41
-} port_generator_t;
42
-
43
-port_generator_t* port_data = NULL;
44
-
45
-int init_port_gen(uint32_t sport_start_val, uint32_t cport_start_val, uint32_t range)
46
-{
47
-    if(sport_start_val < 1 || cport_start_val < 1){
48
-        return 1;
49
-    }
50
-
51
-    if((UINT32_MAX - range < sport_start_val) || (UINT32_MAX - range < cport_start_val)){
52
-        return 2;
53
-    }
54
-
55
-	if(port_data){
56
-		return 3;
57
-	}
58
-
59
-	port_data = shm_malloc(sizeof(port_generator_t));
60
-	if(port_data == NULL){
61
-		return 4;
62
-	}
63
-
64
-	if(pthread_mutex_init(&port_data->sport_mut, NULL)){
65
-		shm_free(port_data);
66
-		return 5;
67
-	}
68
-
69
-	if(pthread_mutex_init(&port_data->cport_mut, NULL)){
70
-		pthread_mutex_destroy(&port_data->sport_mut);
71
-		shm_free(port_data);
72
-		return 6;
73
-	}
74
-
75
-	port_data->used_sports = create_list();
76
-	port_data->used_cports = create_list();
77
-
78
-	port_data->sport_val = port_data->min_sport = sport_start_val;
79
-	port_data->cport_val = port_data->min_cport = cport_start_val;
80
-	port_data->max_sport = sport_start_val + range;
81
-	port_data->max_cport = cport_start_val + range;
82
-
83
-    return 0;
84
-}
85
-
86
-uint32_t acquire_port(spi_list_t* used_ports, pthread_mutex_t* port_mut, uint32_t* port_val, uint32_t min_port, uint32_t max_port)
87
-{
88
-	//save the initial value for the highly unlikely case where there are no free PORTs
89
-    uint32_t initial_val = *port_val;
90
-    uint32_t ret = 0; // by default return invalid port
91
-
92
-    if(pthread_mutex_lock(port_mut) != 0) {
93
-        return ret;
94
-    }
95
-
96
-    while(1){
97
-        if(spi_in_list(used_ports, *port_val) == 0) {
98
-            ret = *port_val;
99
-            (*port_val)++;
100
-
101
-			if(*port_val >= max_port) { //reached the top of the range - reset
102
-				*port_val = min_port;
103
-			}
104
-
105
-            break;
106
-        }
107
-
108
-        (*port_val)++; //the current server port is not available - increment
109
-
110
-        if(*port_val >= max_port) { //reached the top of the range - reset
111
-            *port_val = min_port;
112
-        }
113
-
114
-        if(*port_val == initial_val) { //there are no free server ports
115
-            pthread_mutex_unlock(port_mut);
116
-            return ret;
117
-        }
118
-    }
119
-
120
-    // found unused server port - add it to the used list
121
-    if(spi_add(used_ports, ret) != 0) {
122
-        ret = 0;
123
-    }
124
-
125
-    pthread_mutex_unlock(port_mut);
126
-    return ret;
127
-}
128
-
129
-uint32_t acquire_sport()
130
-{
131
-	if(!port_data){
132
-		return 0;
133
-	}
134
-
135
-	return acquire_port(&port_data->used_sports, &port_data->sport_mut, &port_data->sport_val, port_data->min_sport, port_data->max_sport);
136
-}
137
-
138
-uint32_t acquire_cport()
139
-{
140
-	if(!port_data){
141
-		return 0;
142
-	}
143
-
144
-	return acquire_port(&port_data->used_cports, &port_data->cport_mut, &port_data->cport_val, port_data->min_cport, port_data->max_cport);
145
-}
146
-
147
-int release_sport(uint32_t port)
148
-{
149
-	if(!port_data){
150
-		return 1;
151
-	}
152
-
153
-	if(pthread_mutex_lock(&port_data->sport_mut) != 0){
154
-        return 1;
155
-    }
156
-
157
-	spi_remove(&port_data->used_sports, port);
158
-
159
-	pthread_mutex_unlock(&port_data->sport_mut);
160
-    return 0;
161
-}
162
-
163
-int release_cport(uint32_t port)
164
-{
165
-	if(!port_data){
166
-		return 1;
167
-	}
168
-
169
-	if(pthread_mutex_lock(&port_data->cport_mut) != 0){
170
-        return 1;
171
-    }
172
-
173
-	spi_remove(&port_data->used_cports, port);
174
-
175
-	pthread_mutex_unlock(&port_data->cport_mut);
176
-    return 0;
177
-}
178
-
179
-int clean_port_lists()
180
-{
181
-	if(!port_data){
182
-		return 1;
183
-	}
184
-
185
-	if(pthread_mutex_lock(&port_data->sport_mut) != 0){
186
-		return 1;
187
-	}
188
-
189
-	destroy_list(&port_data->used_sports);
190
-
191
-	pthread_mutex_unlock(&port_data->sport_mut);
192
-
193
-	if(pthread_mutex_lock(&port_data->cport_mut) != 0){
194
-		return 1;
195
-	}
196
-
197
-	destroy_list(&port_data->used_cports);
198
-
199
-	pthread_mutex_unlock(&port_data->cport_mut);
200
-
201
-	return 0;
202
-}
203
-
204
-int destroy_port_gen()
205
-{
206
-	if(!port_data){
207
-		return 1;
208
-	}
209
-
210
-	int ret;
211
-
212
-	destroy_list(&port_data->used_sports);
213
-	destroy_list(&port_data->used_cports);
214
-
215
-	port_data->sport_val = port_data->min_sport;
216
-	port_data->cport_val = port_data->min_cport;
217
-
218
-	ret = pthread_mutex_destroy(&port_data->sport_mut);
219
-    if(ret != 0){
220
-		shm_free(port_data);
221
-        return ret;
222
-    }
223
-
224
-	ret = pthread_mutex_destroy(&port_data->cport_mut);
225
-	shm_free(port_data);
226
-	return ret;
227
-}
228 0
deleted file mode 100644
... ...
@@ -1,41 +0,0 @@
1
-/*
2
- * IMS IPSEC PCSCF module
3
- *
4
- * Copyright (C) 2018 Tsvetomir Dimitrov
5
- * Copyright (C) 2019 Aleksandar Yosifov
6
- *
7
- * This file is part of Kamailio, a free SIP server.
8
- *
9
- * Kamailio is free software; you can redistribute it and/or modify
10
- * it under the terms of the GNU General Public License as published by
11
- * the Free Software Foundation; either version 2 of the License, or
12
- * (at your option) any later version
13
- *
14
- * Kamailio is distributed in the hope that it will be useful,
15
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
- * GNU General Public License for more details.
18
- *
19
- * You should have received a copy of the GNU General Public License
20
- * along with this program; if not, write to the Free Software
21
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
- *
23
- */
24
-
25
-#ifndef _SPI_GEN_H_
26
-
27
-#include <stdint.h>
28
-
29
-//
30
-// PORT GEN is based on SPI list, because the logics of the SPI gen and PORT gen are basically the same.
31
-// It is used as an unique port generator for the TCP client and server ports.
32
-
33
-int init_port_gen(uint32_t sport_start_val, uint32_t cport_start_val, uint32_t range);
34
-int clean_port_lists();
35
-int destroy_port_gen();
36
-uint32_t acquire_sport(); // acquare server port
37
-uint32_t acquire_cport(); // acquare client port
38
-int release_sport(uint32_t port); // release server port
39
-int release_cport(uint32_t port); // release client port
40
-
41
-#endif /*  _SPI_GEN_H_ */
... ...
@@ -25,6 +25,9 @@
25 25
 #include "../../core/parser/msg_parser.h"
26 26
 #include "../../core/mem/mem.h"
27 27
 
28
+extern str ipsec_preferred_alg;
29
+extern str ipsec_preferred_ealg;
30
+
28 31
 static uint32_t parse_digits(str value)
29 32
 {
30 33
     uint32_t ret = 0;
... ...
@@ -68,13 +71,17 @@ static void trim_whitespaces(str* string) {
68 71
         DST.len = SRC.len;
69 72
 
70 73
 
71
-static int process_sec_agree_param(str name, str value, ipsec_t *ret)
74
+static int process_sec_agree_param(str name, str value, ipsec_t *ret, char *alg_found, char *ealg_found)
72 75
 {
73 76
     trim_whitespaces(&name);
74 77
     trim_whitespaces(&value);
75 78
 
76 79
     if(strncasecmp(name.s, "alg", name.len) == 0) {
77 80
         SEC_COPY_STR_PARAM(ret->r_alg, value);
81
+
82
+        if(ipsec_preferred_alg.len && STR_EQ(value, ipsec_preferred_alg)) {
83
+            *alg_found = 1;
84
+        }
78 85
     }
79 86
     else if(strncasecmp(name.s, "prot", name.len) == 0) {
80 87
         SEC_COPY_STR_PARAM(ret->prot, value);
... ...
@@ -84,6 +91,10 @@ static int process_sec_agree_param(str name, str value, ipsec_t *ret)
84 91
     }
85 92
     else if(strncasecmp(name.s, "ealg", name.len) == 0) {
86 93
         SEC_COPY_STR_PARAM(ret->r_ealg, value);
94
+
95
+        if(ipsec_preferred_ealg.len && STR_EQ(value, ipsec_preferred_ealg)) {
96
+            *ealg_found = 1;
97
+        }
87 98
     }
88 99
     else if(strncasecmp(name.s, "spi-c", name.len) == 0) {
89 100
         ret->spi_uc = parse_digits(value);
... ...
@@ -157,11 +168,14 @@ static security_t* parse_sec_agree(struct hdr_field* h)
157 168
     body.s=body.s+i+1;
158 169
     body.len=body.len-i-1;
159 170
 
171
+    char preferred_alg_found  = 0;
172
+    char preferred_ealg_found = 0;
173
+
160 174
     // get the rest of the parameters
161 175
     i = 0;
162 176
     while(i <= body.len) {
163 177
         //look for end of buffer or parameter separator
164
-        if(i == body.len || body.s[i] == ';' ) {
178
+        if(i == body.len || body.s[i] == ';' || body.s[i] == ',' || body.s[i] == ' ') {
165 179
             if(name.len) {
166 180
                 // if(name.len) => a param name is parsed
167 181
                 // and now i points to the end of its value
... ...
@@ -176,9 +190,25 @@ static security_t* parse_sec_agree(struct hdr_field* h)
176 190
             i=0;
177 191
 
178 192
             if(name.len && value.len) {
179
-                if(process_sec_agree_param(name, value, params->data.ipsec)) {
193
+                if(strncasecmp(name.s, "alg", name.len) == 0) {
194
+                    if(preferred_alg_found && preferred_ealg_found) {
195
+                        break;
196
+                    }
197
+                    preferred_alg_found = 0;
198
+                    preferred_ealg_found = 0;
199
+                }
200
+ 
201
+                char alg_found  = 0;
202
+                char ealg_found = 0;
203
+                if(process_sec_agree_param(name, value, params->data.ipsec, &alg_found, &ealg_found)) {
180 204
                     goto cleanup;
181 205
                 }
206
+                if(alg_found) {
207
+                    preferred_alg_found = 1;
208
+                }
209
+                if(ealg_found) {
210
+                    preferred_ealg_found = 1;
211
+                }
182 212
             }
183 213
             //else - something's wrong. Ignore!
184 214
 
... ...
@@ -26,23 +26,65 @@
26 26
 #include <pthread.h>
27 27
 #include "../../core/mem/shm_mem.h"
28 28
 
29
+#define MAX_HASH_SPI 10000
30
+
29 31
 typedef struct spi_generator{
30 32
 	pthread_mutex_t	spis_mut;
31
-	spi_list_t		used_spis;
33
+	spi_list_t	used_spis[MAX_HASH_SPI];
34
+	spi_list_t	free_spi;
32 35
 	uint32_t		spi_val;
33 36
 	uint32_t		min_spi;
34 37
 	uint32_t		max_spi;
38
+	uint32_t		sport_start_val;
39
+	uint32_t		cport_start_val;
40
+	uint32_t		port_range;
35 41
 } spi_generator_t;
36 42
 
37 43
 spi_generator_t* spi_data = NULL;
38 44
 
39
-int init_spi_gen(uint32_t start_val, uint32_t range)
45
+static int init_free_spi()
40 46
 {
41
-    if(start_val < 1) {
47
+	uint32_t sport_start_val, cport_start_val, port_range, sport, cport, j;
48
+
49
+	if(!spi_data) {
50
+		return 1;
51
+	}
52
+
53
+	sport_start_val = spi_data->sport_start_val;
54
+	cport_start_val = spi_data->cport_start_val;
55
+	port_range = spi_data->port_range;
56
+	//save the initial value for the highly unlikely case where there are no free SPIs
57
+	sport = sport_start_val;
58
+	cport = cport_start_val;
59
+
60
+	spi_data->free_spi = create_list();
61
+	for(j = spi_data->min_spi; j < spi_data->max_spi; j+=2)
62
+	{
63
+		spi_add(&spi_data->free_spi, j, j+1, cport, sport);
64
+		cport++;
65
+		sport++;
66
+
67
+		if(cport >= cport_start_val + port_range) {
68
+			cport = cport_start_val;
69
+		}
70
+
71
+		if(sport >= sport_start_val + port_range) {
72
+			sport = sport_start_val;
73
+		}
74
+	}
75
+
76
+	return 0;
77
+}
78
+
79
+int init_spi_gen(uint32_t spi_start_val, uint32_t spi_range, uint32_t sport_start_val, uint32_t cport_start_val, uint32_t port_range)
80
+{
81
+    uint32_t j;
82
+
83
+    if(spi_start_val < 1) {
42 84
         return 1;
43 85
     }
44 86
 
45
-    if(UINT32_MAX - range < start_val) {
87
+    if(UINT32_MAX - spi_range < spi_start_val) {
46 88
         return 2;
47 89
     }
48 90
 
... ...
@@ -64,67 +106,60 @@ int init_spi_gen(uint32_t start_val, uint32_t range)
64 106
 		return 6;
65 107
 	}
66 108
 
67
-    spi_data->used_spis = create_list();
109
+    for(j = 0; j < MAX_HASH_SPI; j++) {
110
+        spi_data->used_spis[j] = create_list();
111
+    }
112
+
113
+    spi_data->spi_val  = spi_data->min_spi = spi_start_val;
114
+    spi_data->max_spi  = spi_start_val + spi_range;
115
+    spi_data->sport_start_val = sport_start_val;
116
+    spi_data->cport_start_val = cport_start_val;
117
+    spi_data->port_range = port_range;
68 118
 
69
-    spi_data->spi_val = spi_data->min_spi = start_val;
70
-    spi_data->max_spi = start_val + range;
119
+	if(init_free_spi() != 0) {
120
+		return 7;
121
+	}
71 122
 
72 123
 	pthread_mutex_unlock(&spi_data->spis_mut);
73 124
 
74 125
     return 0;
75 126
 }
76 127
 
77
-uint32_t acquire_spi()
128
+uint32_t acquire_spi(uint32_t* spi_cid, uint32_t* spi_sid, uint16_t* cport, uint16_t* sport)
78 129
 {
79 130
 	if(!spi_data){
131
+		LM_ERR("spi_data is NULL\n");
80 132
 		return 0;
81 133
 	}
82 134
 
83 135
 	if(pthread_mutex_lock(&spi_data->spis_mut) != 0){
136
+		LM_ERR("spi_data failed to lock\n");
84 137
 		return 0;
85 138
 	}
86 139
 
87
-    //save the initial value for the highly unlikely case where there are no free SPIs
88
-	uint32_t initial_val = spi_data->spi_val;
89
-    uint32_t ret = 0; // by default return invalid SPI
90
-
91
-    while(1) {
92
-		if(spi_in_list(&spi_data->used_spis, spi_data->spi_val) == 0){
93
-			ret = spi_data->spi_val;
94
-			spi_data->spi_val++;
95
-
96
-			if(spi_data->spi_val >= spi_data->max_spi) { //reached the top of the range - reset
97
-				spi_data->spi_val = spi_data->min_spi;
98
-			}
99
-
100
-            break;
101
-        }
102
-
103
-		spi_data->spi_val++; //the current SPI is not available - increment
104
-
105
-		if(spi_data->spi_val >= spi_data->max_spi){ //reached the top of the range - reset
106
-			spi_data->spi_val = spi_data->min_spi;
107
-        }
108
-
109
-		if(spi_data->spi_val == initial_val){ //there are no free SPIs
110
-			pthread_mutex_unlock(&spi_data->spis_mut);
111
-            return ret;
112
-        }
113
-
140
+    if(!spi_data->free_spi.head)
141
+    {
142
+        LM_ERR("spi_data:%p spi_data->free_spi.head %p\n", spi_data, spi_data->free_spi.head);
143
+        pthread_mutex_unlock(&spi_data->spis_mut);
144
+        return 0;
114 145
     }
115 146
 
116
-    //found unused SPI - add it to the used list
117
-	if(spi_add(&spi_data->used_spis, ret) != 0){
118
-        ret = 0;
119
-    }
147
+    *spi_cid = spi_data->free_spi.head->spi_cid;
148
+    *spi_sid = spi_data->free_spi.head->spi_sid;
149
+    *sport   = spi_data->free_spi.head->sport;
150
+    *cport   = spi_data->free_spi.head->cport;
151
+    spi_remove_head(&spi_data->free_spi);
152
+    spi_add(&spi_data->used_spis[*spi_cid % MAX_HASH_SPI], *spi_cid, *spi_sid, *cport, *sport);
153
+    pthread_mutex_unlock(&spi_data->spis_mut);
120 154
 
121
-	pthread_mutex_unlock(&spi_data->spis_mut);
155
+    LM_DBG("spi acquired spi_cid:%u spi_sid:%u sport:%u cport:%u \n",  *spi_cid, *spi_sid, *sport, *cport);
122 156
 
123
-    return ret;
157
+    return 1;
124 158
 }
125 159
 
126
-int release_spi(uint32_t id)
160
+int release_spi(uint32_t spi_cid, uint32_t spi_sid, uint16_t cport, uint16_t sport)
127 161
 {
162
+	LM_DBG("releasing spi spi_data:%p spi_cid:%u spi_sid:%u cport:%u sport:%u\n", spi_data, spi_cid, spi_sid, cport, sport);
128 163
 	if(!spi_data){
129 164
 		return 1;
130 165
 	}
... ...
@@ -133,7 +168,11 @@ int release_spi(uint32_t id)
133 168
         return 1;
134 169
     }
135 170
 
136
-	spi_remove(&spi_data->used_spis, id);
171
+    // if we successfully remove from used spi we will insert into free spi
172
+    if(spi_remove(&spi_data->used_spis[spi_cid % MAX_HASH_SPI], spi_cid, spi_sid))
173
+    {
174
+        spi_add(&spi_data->free_spi, spi_cid, spi_sid, cport, sport);
175
+    }
137 176
 
138 177
 	pthread_mutex_unlock(&spi_data->spis_mut);
139 178
 
... ...
@@ -142,6 +181,8 @@ int release_spi(uint32_t id)
142 181
 
143 182
 int clean_spi_list()
144 183
 {
184
+	uint32_t j;
185
+
145 186
 	if(!spi_data){
146 187
 		return 1;
147 188
 	}
... ...
@@ -150,7 +191,13 @@ int clean_spi_list()
150 191
 		return 1;
151 192
 	}
152 193
 
153
-	destroy_list(&spi_data->used_spis);
194
+	for(j = 0; j < MAX_HASH_SPI; j++) {
195
+		destroy_list(&spi_data->used_spis[j]);
196
+	}
197
+
198
+	destroy_list(&spi_data->free_spi);
199
+	init_free_spi();
200
+
154 201
 	spi_data->spi_val = spi_data->min_spi;
155 202
 
156 203
 	pthread_mutex_unlock(&spi_data->spis_mut);
... ...
@@ -164,7 +211,7 @@ int destroy_spi_gen()
164 211
 		return 1;
165 212
 	}
166 213
 
167
-	destroy_list(&spi_data->used_spis);
214
+	clean_spi_list();
168 215
 
169 216
 	int ret = pthread_mutex_destroy(&spi_data->spis_mut);
170 217
 	shm_free(spi_data);
... ...
@@ -31,10 +31,10 @@
31 31
 // is important not to use generate ID which is still in use. For this reason there are
32 32
 // acquire_spi() and release_spi(uint32_t id) functions.
33 33
 
34
-int init_spi_gen(uint32_t start_val, uint32_t range);
34
+int init_spi_gen(uint32_t spi_start_val, uint32_t spi_range, uint32_t sport_start_val, uint32_t cport_start_val, uint32_t port_range);
35 35
 int clean_spi_list();
36 36
 int destroy_spi_gen();
37
-uint32_t acquire_spi();
38
-int release_spi(uint32_t id);
37
+uint32_t acquire_spi(uint32_t* spi_cid, uint32_t* spi_sid, uint16_t* cport, uint16_t* sport);
38
+int release_spi(uint32_t spi_cid, uint32_t spi_sid, uint16_t cport, uint16_t sport);
39 39
 
40 40
 #endif /*  _SPI_GEN_H_ */
... ...
@@ -50,7 +50,7 @@ void destroy_list(spi_list_t* lst)
50 50
 	lst->tail = NULL;
51 51
 }
52 52
 
53
-int spi_add(spi_list_t* list, uint32_t id)
53
+int spi_add(spi_list_t* list, uint32_t spi_cid, uint32_t spi_sid, uint16_t sport, uint16_t cport)
54 54
 {
55 55
 	if(!list){
56 56
 		return 1;
... ...
@@ -62,7 +62,10 @@ int spi_add(spi_list_t* list, uint32_t id)
62 62
         return 1;
63 63
 
64 64
     n->next = NULL;
65
-    n->id = id;
65
+    n->spi_cid = spi_cid;
66
+    n->spi_sid = spi_sid;
67
+    n->sport   = sport;
68
+    n->cport   = cport;
66 69
 
67 70
     //when list is empty
68 71
     if(!list->head) {
... ...
@@ -71,37 +74,31 @@ int spi_add(spi_list_t* list, uint32_t id)
71 74
         return 0;
72 75
     }
73 76
 
74
-    //all other cases - list should be sorted
75
-    spi_node_t* c = list->head;
76
-    spi_node_t* p = NULL;
77
-    while(c && (n->id > c->id)) {
78
-        p = c;
79
-        c = c->next;
80
-    }
77
+    list->tail->next = n;
78
+    list->tail = n;
81 79
 
80
+    return 0;
81
+}
82 82
 
83
-    if(c == NULL) { //first of all - at the end of the list?
84
-        list->tail->next = n;
85
-        list->tail = n;
86
-    }
87
-    else if(n->id == c->id) { //c is not NULL, so check for duplicates
88
-        shm_free(n);
83
+int spi_remove_head(spi_list_t* list)
84
+{
85
+    if(!list) {
89 86
         return 1;
90 87
     }
91
-    else if(c == list->head) { //at the start of the list?
92
-        n->next = list->head;
93
-        list->head = n;
94
-    }
95
-    else {  //not a special case - just add it
96
-        p->next = n;
97
-        n->next = c;
88
+
89
+    //when list is empty
90
+    if(!list->head) {
91
+        return 1;
98 92
     }
99 93
 
94
+    spi_node_t* t = list->head;
95
+    list->head = t->next;
96
+    shm_free(t);
97
+
100 98
     return 0;
101 99
 }
102 100
 
103
-
104
-int spi_remove(spi_list_t* list, uint32_t id)
101
+int spi_remove(spi_list_t* list, uint32_t spi_cid, uint32_t spi_sid)
105 102
 {
106 103
 	if(!list){
107 104
 		return 0;
... ...
@@ -113,7 +110,7 @@ int spi_remove(spi_list_t* list, uint32_t id)
113 110
     }
114 111
 
115 112
     //when target is head
116
-    if(list->head->id == id) {
113
+    if(list->head->spi_cid == spi_cid && list->head->spi_sid == spi_sid) {
117 114
         spi_node_t* t = list->head;
118 115
         list->head = t->next;
119 116
 
... ...
@@ -123,7 +120,7 @@ int spi_remove(spi_list_t* list, uint32_t id)
123 120
         }
124 121
 
125 122
 		shm_free(t);
126
-        return 0;
123
+        return 1;
127 124
     }
128 125
 
129 126
 
... ...
@@ -131,7 +128,7 @@ int spi_remove(spi_list_t* list, uint32_t id)
131 128
     spi_node_t* curr = list->head->next;
132 129
 
133 130
     while(curr) {
134
-        if(curr->id == id) {
131
+        if(curr->spi_cid == spi_cid && curr->spi_sid == spi_sid) {
135 132
             spi_node_t* t = curr;
136 133
 
137 134
             //detach node
... ...
@@ -143,7 +140,7 @@ int spi_remove(spi_list_t* list, uint32_t id)
143 140
             }
144 141
 
145 142
 			shm_free(t);
146
-            return 0;
143
+            return 1;
147 144
         }
148 145
 
149 146
         prev = curr;
... ...
@@ -153,7 +150,7 @@ int spi_remove(spi_list_t* list, uint32_t id)
153 150
     return -1; // out of scope
154 151
 }
155 152
 
156
-int spi_in_list(spi_list_t* list, uint32_t id)
153
+int spi_in_list(spi_list_t* list, uint32_t spi_cid, uint32_t spi_sid)
157 154
 {
158 155
 	if(!list){
159 156
 		return 0;
... ...
@@ -162,14 +159,11 @@ int spi_in_list(spi_list_t* list, uint32_t id)
162 159
     if(!list->head)
163 160
         return 0;
164 161
 
165
-    if(id < list->head->id || id > list->tail->id)
166
-        return 0;
167
-
168 162
     spi_node_t* n = list->head;
169 163
     while(n) {
170
-        if (n->id == id)
164
+        if (n->spi_cid == spi_cid && n->spi_sid == spi_sid) {
171 165
             return 1;
172
-        
166
+        }
173 167
         n = n->next;
174 168
     }
175 169
 
... ...
@@ -35,7 +35,10 @@ typedef struct _spi_node spi_node_t;
35 35
 
36 36
 struct _spi_node {
37 37
     spi_node_t* next;
38
-    uint32_t id;
38
+    uint32_t spi_cid;
39
+    uint32_t spi_sid;
40
+    uint16_t sport;
41
+    uint16_t cport;
39 42
 };
40 43
 
41 44
 typedef struct _spi_list {
... ...
@@ -46,8 +49,9 @@ typedef struct _spi_list {
46 49
 
47 50
 spi_list_t create_list();
48 51
 void destroy_list(spi_list_t* lst);
49
-int spi_add(spi_list_t* list, uint32_t id);
50
-int spi_remove(spi_list_t* list, uint32_t id);
51
-int spi_in_list(spi_list_t* list, uint32_t id);
52
+int spi_add(spi_list_t* list, uint32_t spi_cid, uint32_t spi_sid, uint16_t cport, uint16_t sport);
53
+int spi_remove_head(spi_list_t* list);
54
+int spi_remove(spi_list_t* list, uint32_t spi_cid, uint32_t spi_sid);
55
+int spi_in_list(spi_list_t* list, uint32_t spi_cid, uint32_t spi_sid);
52 56
 
53 57
 #endif /* _SPI_LIST_H_ */