blob: aa8b121aee6876fee0a836b15c0c3d710f18787e [file] [log] [blame]
Harald Welte047f3872018-07-01 21:04:45 +02001/* Implementation of 3GPP TS 48.016 NS IP Sub-Network Service */
2/* (C) 2018 by Harald Welte <laforge@gnumonks.org> */
3
4/* The BSS NSE only has one SGSN IP address configured, and it will use the SNS procedures
5 * to communicated its local IPs/ports as well as all the SGSN side IPs/ports and
6 * associated weights. In theory, the BSS then uses this to establish a full mesh
7 * of NSVCs between all BSS-side IPs/ports and SGSN-side IPs/ports */
8
9#include <errno.h>
10
11#include <netinet/in.h>
12#include <arpa/inet.h>
13
14#include <osmocom/core/fsm.h>
15#include <osmocom/core/msgb.h>
16#include <osmocom/core/signal.h>
17#include <osmocom/core/socket.h>
18#include <osmocom/gsm/tlv.h>
19#include <osmocom/gprs/gprs_msgb.h>
20#include <osmocom/gprs/gprs_ns.h>
21
22#include "common_vty.h"
23#include "gb_internal.h"
24
25#define S(x) (1 << (x))
26
27struct gprs_sns_state {
28 struct gprs_ns_inst *nsi;
29 struct gprs_nsvc *nsvc_hack;
30
31 /* local configuration to send to the remote end */
32 struct gprs_ns_ie_ip4_elem *ip4_local;
33 size_t num_ip4_local;
34
35 /* local configuration about our capabilities in terms of connections to
36 * remote (SGSN) side */
37 size_t num_max_nsvcs;
38 size_t num_max_ip4_remote;
39
40 /* remote configuration as received */
41 struct gprs_ns_ie_ip4_elem *ip4_remote;
42 unsigned int num_ip4_remote;
43
44 /* IP-SNS based Gb doesn't have a NSVCI. However, our existing Gb stack
45 * requires a unique NSVCI per NS-VC. Let's simply allocate them dynamically from
46 * the maximum (65533), counting downwards */
47 uint16_t next_nsvci;
48};
49
50static inline struct gprs_ns_inst *ns_inst_from_fi(struct osmo_fsm_inst *fi)
51{
52 struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
53 return gss->nsi;
54}
55
56/* helper function to compute the sum of all (data or signaling) weights */
57static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,
58 bool data_weight)
59{
60 unsigned int i;
61 int weight_sum = 0;
62
63 for (i = 0; i < num; i++) {
64 if (data_weight)
65 weight_sum += ip4[i].data_weight;
66 else
67 weight_sum += ip4[i].sig_weight;
68 }
69 return weight_sum;
70}
71#define ip4_weight_sum_data(x,y) ip4_weight_sum(x, y, true)
72#define ip4_weight_sum_sig(x,y) ip4_weight_sum(x, y, false)
73
74static struct gprs_nsvc *nsvc_by_ip4_elem(struct gprs_ns_inst *nsi,
75 const struct gprs_ns_ie_ip4_elem *ip4)
76{
77 struct sockaddr_in sin;
78 /* copy over. Both data structures use network byte order */
79 sin.sin_addr.s_addr = ip4->ip_addr;
80 sin.sin_port = ip4->udp_port;
81 return gprs_nsvc_by_rem_addr(nsi, &sin);
82}
83
84static struct gprs_nsvc *gprs_nsvc_create_ip4(struct gprs_ns_inst *nsi,
85 const struct gprs_ns_ie_ip4_elem *ip4)
86{
87 struct gprs_sns_state *gss = (struct gprs_sns_state *) nsi->bss_sns_fi->priv;
88 struct gprs_nsvc *nsvc;
89 struct sockaddr_in sin;
90 /* copy over. Both data structures use network byte order */
Harald Weltefa90cfd2019-03-20 08:30:29 +010091 memset(&sin, 0, sizeof(sin));
92 sin.sin_family = AF_INET;
Harald Welte047f3872018-07-01 21:04:45 +020093 sin.sin_addr.s_addr = ip4->ip_addr;
94 sin.sin_port = ip4->udp_port;
95
96 nsvc = gprs_nsvc_create2(nsi, gss->next_nsvci--, ip4->sig_weight, ip4->data_weight);
97 if (!nsvc)
98 return NULL;
99
100 /* NSEI is the same across all NS-VCs */
101 nsvc->nsei = gss->nsvc_hack->nsei;
102 nsvc->nsvci_is_valid = 0;
103 nsvc->ip.bts_addr = sin;
104
105 return nsvc;
106}
107
108static int create_missing_nsvcs(struct osmo_fsm_inst *fi)
109{
110 struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
111 struct gprs_ns_inst *nsi = ns_inst_from_fi(fi);
112 unsigned int i;
113
114 for (i = 0; i < gss->num_ip4_remote; i++) {
115 const struct gprs_ns_ie_ip4_elem *ip4 = &gss->ip4_remote[i];
116 struct gprs_nsvc *nsvc = nsvc_by_ip4_elem(nsi, ip4);
117 if (!nsvc) {
118 /* create, if it doesn't exist */
119 nsvc = gprs_nsvc_create_ip4(nsi, ip4);
120 if (!nsvc) {
121 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG: Failed to create NSVC\n");
122 continue;
123 }
124 } else {
125 /* update data / signalling weight */
126 nsvc->data_weight = ip4->data_weight;
127 nsvc->sig_weight = ip4->sig_weight;
128 }
129 LOGPFSML(fi, LOGL_INFO, "NS-VC %s data_weight=%u, sig_weight=%u\n",
130 gprs_ns_ll_str(nsvc), nsvc->data_weight, nsvc->sig_weight);
131 }
132
133 return 0;
134}
135
136/* Add a given remote IPv4 element to gprs_sns_state */
137static int add_remote_ip4_elem(struct gprs_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
138{
139 if (gss->num_ip4_remote >= gss->num_max_ip4_remote)
140 return -E2BIG;
141
142 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote, struct gprs_ns_ie_ip4_elem,
143 gss->num_ip4_remote+1);
144 gss->ip4_remote[gss->num_ip4_remote] = *ip4;
145 gss->num_ip4_remote += 1;
146 return 0;
147}
148
149/* Remove a given remote IPv4 element from gprs_sns_state */
150static int remove_remote_ip4_elem(struct gprs_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
151{
152 unsigned int i;
153
154 for (i = 0; i < gss->num_ip4_remote; i++) {
155 if (memcmp(&gss->ip4_remote[i], ip4, sizeof(*ip4)))
156 continue;
157 /* all array elements < i remain as they are; all > i are shifted left by one */
158 memmove(&gss->ip4_remote[i], &gss->ip4_remote[i+1], gss->num_ip4_remote-i-1);
159 gss->num_ip4_remote -= 1;
160 return 0;
161 }
162 return -1;
163}
164
165/* update the weights for specified remote IPv4 */
166static int update_remote_ip4_elem(struct gprs_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
167{
168 unsigned int i;
169
170 for (i = 0; i < gss->num_ip4_remote; i++) {
171 if (gss->ip4_remote[i].ip_addr != ip4->ip_addr ||
172 gss->ip4_remote[i].udp_port != ip4->udp_port)
173 continue;
174 gss->ip4_remote[i].sig_weight = ip4->sig_weight;
175 gss->ip4_remote[i].data_weight = ip4->data_weight;
176 return 0;
177 }
178 return -1;
179}
180
181
182static int do_sns_change_weight(struct osmo_fsm_inst *fi, const struct gprs_ns_ie_ip4_elem *ip4)
183{
184 struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
185 struct gprs_ns_inst *nsi = ns_inst_from_fi(fi);
186 struct gprs_nsvc *nsvc = nsvc_by_ip4_elem(nsi, ip4);
187
188 /* TODO: Upon receiving an SNS-CHANGEWEIGHT PDU, if the resulting sum of the
189 * signalling weights of all the peer IP endpoints configured for this NSE is
190 * equal to zero or if the resulting sum of the data weights of all the peer IP
191 * endpoints configured for this NSE is equal to zero, the BSS/SGSN shall send an
192 * SNS-ACK PDU with a cause code of "Invalid weights". */
193
194 update_remote_ip4_elem(gss, ip4);
195
196 if (!nsvc) {
197 LOGPFSML(fi, LOGL_NOTICE, "Couldn't find NS-VC for SNS-CHANGE_WEIGHT\n");
198 return -NS_CAUSE_NSVC_UNKNOWN;
199 }
200
201 LOGPFSML(fi, LOGL_INFO, "CHANGE-WEIGHT NS-VC %s data_weight %u->%u, sig_weight %u->%u\n",
202 gprs_ns_ll_str(nsvc), nsvc->data_weight, ip4->data_weight,
203 nsvc->sig_weight, ip4->sig_weight);
204
205 nsvc->data_weight = ip4->data_weight;
206 nsvc->sig_weight = ip4->sig_weight;
207
208 return 0;
209}
210
211static int do_sns_delete(struct osmo_fsm_inst *fi, const struct gprs_ns_ie_ip4_elem *ip4)
212{
213 struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
214 struct gprs_ns_inst *nsi = ns_inst_from_fi(fi);
215 struct gprs_nsvc *nsvc = nsvc_by_ip4_elem(nsi, ip4);
216
217 if (remove_remote_ip4_elem(gss, ip4) < 0)
218 return -NS_CAUSE_UNKN_IP_EP;
219
220 if (!nsvc) {
221 LOGPFSML(fi, LOGL_NOTICE, "Couldn't find NS-VC for SNS-DELETE\n");
222 return -NS_CAUSE_NSVC_UNKNOWN;
223 }
224 LOGPFSML(fi, LOGL_INFO, "DELETE NS-VC %s\n", gprs_ns_ll_str(nsvc));
225 gprs_nsvc_delete(nsvc);
226
227 return 0;
228}
229
230static int do_sns_add(struct osmo_fsm_inst *fi, const struct gprs_ns_ie_ip4_elem *ip4)
231{
232 struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
233 struct gprs_ns_inst *nsi = ns_inst_from_fi(fi);
234 struct gprs_nsvc *nsvc;
235
236 /* Upon receiving an SNS-ADD PDU, if the consequent number of IPv4 endpoints
237 * exceeds the number of IPv4 endpoints supported by the NSE, the NSE shall send
238 * an SNS-ACK PDU with a cause code set to "Invalid number of IP4 Endpoints". */
239 if (add_remote_ip4_elem(gss, ip4) < 0)
240 return -NS_CAUSE_INVAL_NR_NS_VC;
241
242 /* Upon receiving an SNS-ADD PDU containing an already configured IP endpoint the
243 * NSE shall send an SNS-ACK PDU with the cause code "Protocol error -
244 * unspecified" */
245 nsvc = nsvc_by_ip4_elem(nsi, ip4);
246 if (nsvc)
247 return -NS_CAUSE_PROTO_ERR_UNSPEC;
248
249 nsvc = gprs_nsvc_create_ip4(nsi, ip4);
250 if (!nsvc) {
251 LOGPFSML(fi, LOGL_ERROR, "SNS-ADD: Failed to create NSVC\n");
252 remove_remote_ip4_elem(gss, ip4);
253 return -NS_CAUSE_EQUIP_FAIL;
254 }
255 LOGPFSML(fi, LOGL_INFO, "ADD NS-VC %s data_weight=%u, sig_weight=%u\n",
256 gprs_ns_ll_str(nsvc), nsvc->data_weight, nsvc->sig_weight);
257 /* Start the test procedure for this new NS-VC */
258 gprs_nsvc_start_test(nsvc);
259 return 0;
260}
261
262
263
264/***********************************************************************
265 * BSS-side FSM for IP Sub-Network Service
266 ***********************************************************************/
267
268enum gprs_sns_bss_state {
269 GPRS_SNS_ST_UNCONFIGURED,
270 GPRS_SNS_ST_SIZE, /*!< SNS-SIZE procedure ongoing */
271 GPRS_SNS_ST_CONFIG_BSS, /*!< SNS-CONFIG procedure (BSS->SGSN) ongoing */
272 GPRS_SNS_ST_CONFIG_SGSN, /*!< SNS-CONFIG procedure (SGSN->BSS) ongoing */
273 GPRS_SNS_ST_CONFIGURED,
274};
275
276enum gprs_sns_event {
277 GPRS_SNS_EV_START,
278 GPRS_SNS_EV_SIZE,
279 GPRS_SNS_EV_SIZE_ACK,
280 GPRS_SNS_EV_CONFIG,
281 GPRS_SNS_EV_CONFIG_END, /*!< SNS-CONFIG with end flag received */
282 GPRS_SNS_EV_CONFIG_ACK,
283 GPRS_SNS_EV_ADD,
284 GPRS_SNS_EV_DELETE,
285 GPRS_SNS_EV_CHANGE_WEIGHT,
286};
287
288static const struct value_string gprs_sns_event_names[] = {
289 { GPRS_SNS_EV_START, "START" },
290 { GPRS_SNS_EV_SIZE, "SIZE" },
291 { GPRS_SNS_EV_SIZE_ACK, "SIZE_ACK" },
292 { GPRS_SNS_EV_CONFIG, "CONFIG" },
293 { GPRS_SNS_EV_CONFIG_END, "CONFIG_END" },
294 { GPRS_SNS_EV_CONFIG_ACK, "CONFIG_ACK" },
295 { GPRS_SNS_EV_ADD, "ADD" },
296 { GPRS_SNS_EV_DELETE, "DELETE" },
297 { GPRS_SNS_EV_CHANGE_WEIGHT, "CHANGE_WEIGHT" },
298 { 0, NULL }
299};
300
301static void gprs_sns_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
302{
303 struct gprs_ns_inst *nsi = ns_inst_from_fi(fi);
304 switch (event) {
305 case GPRS_SNS_EV_START:
306 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
307 break;
308 default:
309 OSMO_ASSERT(0);
310 }
311}
312
313static void gprs_sns_st_size(struct osmo_fsm_inst *fi, uint32_t event, void *data)
314{
315 struct gprs_ns_inst *nsi = ns_inst_from_fi(fi);
316 struct tlv_parsed *tp = NULL;
317
318 switch (event) {
319 case GPRS_SNS_EV_SIZE_ACK:
320 tp = data;
321 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
322 LOGPFSML(fi, LOGL_ERROR, "SNS-SIZE-ACK with cause %s\n",
323 gprs_ns_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
324 /* FIXME: What to do? */
325 } else {
326 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS,
327 nsi->timeout[NS_TOUT_TSNS_PROV], 2);
328 }
329 break;
330 default:
331 OSMO_ASSERT(0);
332 }
333}
334static void gprs_sns_st_size_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
335{
336 struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
337 uint16_t num_max_ip4_remote = gss->num_max_ip4_remote;
338
339 gprs_ns_tx_sns_size(gss->nsvc_hack, true, gss->num_max_nsvcs, &num_max_ip4_remote, NULL);
340}
341
342
343static void gprs_sns_st_config_bss(struct osmo_fsm_inst *fi, uint32_t event, void *data)
344{
345 //struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
346 //struct gprs_ns_inst *nsi = ns_inst_from_fi(fi);
347 struct tlv_parsed *tp = NULL;
348
349 switch (event) {
350 case GPRS_SNS_EV_CONFIG_ACK:
351 tp = data;
352 if (TLVP_VAL_MINLEN(tp, NS_IE_CAUSE, 1)) {
353 LOGPFSML(fi, LOGL_ERROR, "SNS-CONFIG-ACK with cause %s\n",
354 gprs_ns_cause_str(*TLVP_VAL(tp, NS_IE_CAUSE)));
355 /* FIXME: What to do? */
356 } else {
357 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, 0, 0);
358 }
359 break;
360 default:
361 OSMO_ASSERT(0);
362 }
363}
364static void gprs_sns_st_config_bss_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
365{
366 struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
367 /* Transmit SNS-CONFIG */
368 gprs_ns_tx_sns_config(gss->nsvc_hack, true, gss->ip4_local, gss->num_ip4_local);
369}
370
371static void gprs_sns_st_config_sgsn(struct osmo_fsm_inst *fi, uint32_t event, void *data)
372{
373 struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
374 struct tlv_parsed *tp = NULL;
375 struct gprs_ns_inst *nsi = ns_inst_from_fi(fi);
376 const struct gprs_ns_ie_ip4_elem *v4_list;
377 unsigned int num_v4;
378 uint8_t cause;
379
380 switch (event) {
381 case GPRS_SNS_EV_CONFIG_END:
382 case GPRS_SNS_EV_CONFIG:
383 tp = data;
384#if 0 /* part of incoming SNS-SIZE (doesn't happen on BSS side */
385 if (TLVP_PRESENT(tp, NS_IE_RESET_FLAG)) {
386 /* reset all existing config */
387 if (gss->ip4_remote)
388 talloc_free(gss->ip4_remote);
389 gss->num_ip4_remote = 0;
390 }
391#endif
392 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
393 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
394 gprs_ns_tx_sns_config_ack(gss->nsvc_hack, &cause);
395 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
396 break;
397 }
398 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
399 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
400 /* realloc to the new size */
401 gss->ip4_remote = talloc_realloc(gss, gss->ip4_remote,
402 struct gprs_ns_ie_ip4_elem,
403 gss->num_ip4_remote+num_v4);
404 /* append the new entries to the end of the list */
405 memcpy(&gss->ip4_remote[gss->num_ip4_remote], v4_list, num_v4*sizeof(*v4_list));
406 gss->num_ip4_remote += num_v4;
407
408 LOGPFSML(fi, LOGL_INFO, "Rx SNS-CONFIG: Remote IPv4 list now %u entries\n",
409 gss->num_ip4_remote);
410 if (event == GPRS_SNS_EV_CONFIG_END) {
411 /* check if sum of data / sig weights == 0 */
412 if (ip4_weight_sum_data(gss->ip4_remote, gss->num_ip4_remote) == 0 ||
413 ip4_weight_sum_sig(gss->ip4_remote, gss->num_ip4_remote) == 0) {
414 cause = NS_CAUSE_INVAL_WEIGH;
415 gprs_ns_tx_sns_config_ack(gss->nsvc_hack, &cause);
416 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_UNCONFIGURED, 0, 0);
417 break;
418 }
419 create_missing_nsvcs(fi);
420 gprs_ns_tx_sns_config_ack(gss->nsvc_hack, NULL);
421 /* start the test procedure on ALL NSVCs! */
422 gprs_start_alive_all_nsvcs(nsi);
423 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
424 } else {
425 /* just send CONFIG-ACK */
426 gprs_ns_tx_sns_config_ack(gss->nsvc_hack, NULL);
427 }
428 break;
429 default:
430 OSMO_ASSERT(0);
431 }
432}
433
434static void gprs_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
435{
436 struct gprs_sns_state *gss = (struct gprs_sns_state *) fi->priv;
437 struct tlv_parsed *tp = NULL;
438 const struct gprs_ns_ie_ip4_elem *v4_list = NULL;
439 unsigned int num_v4 = 0;
440 uint8_t trans_id;
441 uint8_t cause = 0xff;
442 unsigned int i;
443 int rc;
444
445 switch (event) {
446 case GPRS_SNS_EV_ADD:
447 tp = data;
448 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
449 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
450 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
451 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
452 for (i = 0; i < num_v4; i++) {
453 rc = do_sns_add(fi, &v4_list[i]);
454 if (rc < 0) {
455 unsigned int j;
456 /* rollback/undo to restore previous state */
457 for (j = 0; j < i; j++)
458 do_sns_delete(fi, &v4_list[j]);
459 cause = -rc;
460 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, &cause, NULL, 0);
461 break;
462 }
463 }
464 } else {
465 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
466 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, &cause, NULL, 0);
467 break;
468 }
469 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, NULL, v4_list, num_v4);
470 break;
471 case GPRS_SNS_EV_DELETE:
472 tp = data;
473 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
474 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
475 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
476 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
477 for (i = 0; i < num_v4; i++) {
478 rc = do_sns_delete(fi, &v4_list[i]);
479 if (rc < 0) {
480 cause = -rc;
481 /* continue to delete others */
482 }
483 }
484 if (cause != 0xff) {
485 /* TODO: create list of not-deleted and return it */
486 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, &cause, NULL, 0);
487 break;
488 }
489 } else if (TLVP_PRES_LEN(tp, NS_IE_IP_ADDR, 5)) {
490 /* delete all NS-VCs for given IP address */
491 const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
492 struct gprs_ns_ie_ip4_elem *ip4_remote;
493 uint32_t ip_addr = *(uint32_t *)(ie+1);
494 if (ie[0] != 0x01) { /* Address Type != IPv4 */
495 cause = NS_CAUSE_UNKN_IP_ADDR;
496 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, &cause, NULL, 0);
497 break;
498 }
499 /* make a copy as do_sns_delete() will change the array underneath us */
500 ip4_remote = talloc_memdup(fi, gss->ip4_remote,
Vadim Yanitskiyb7344d02019-04-12 21:48:07 +0700501 gss->num_ip4_remote*sizeof(*v4_list));
Harald Welte047f3872018-07-01 21:04:45 +0200502 for (i = 0; i < gss->num_ip4_remote; i++) {
503 if (ip4_remote[i].ip_addr == ip_addr) {
504 rc = do_sns_delete(fi, &ip4_remote[i]);
505 if (rc < 0) {
506 cause = -rc;
507 /* continue to delete others */
508 }
509 }
510 }
511 talloc_free(ip4_remote);
512 if (cause != 0xff) {
513 /* TODO: create list of not-deleted and return it */
514 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, &cause, NULL, 0);
515 break;
516 }
517 } else {
518 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
519 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, &cause, NULL, 0);
520 break;
521 }
522 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, NULL, v4_list, num_v4);
523 break;
524 case GPRS_SNS_EV_CHANGE_WEIGHT:
525 tp = data;
526 trans_id = *TLVP_VAL(tp, NS_IE_TRANS_ID);
527 if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
528 v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
529 num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
530 for (i = 0; i < num_v4; i++) {
531 rc = do_sns_change_weight(fi, &v4_list[i]);
532 if (rc < 0) {
533 cause = -rc;
534 /* continue to others */
535 }
536 }
537 if (cause != 0xff) {
538 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, &cause, NULL, 0);
539 break;
540 }
541 } else {
542 cause = NS_CAUSE_INVAL_NR_IPv4_EP;
543 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, &cause, NULL, 0);
544 break;
545 }
546 gprs_ns_tx_sns_ack(gss->nsvc_hack, trans_id, NULL, v4_list, num_v4);
547 break;
548 }
549}
550
551static void gprs_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
552{
553 struct ns_signal_data nssd = {0};
554 osmo_signal_dispatch(SS_L_NS, S_SNS_CONFIGURED, &nssd);
555}
556
557static const struct osmo_fsm_state gprs_sns_bss_states[] = {
558 [GPRS_SNS_ST_UNCONFIGURED] = {
559 .in_event_mask = S(GPRS_SNS_EV_START),
560 .out_state_mask = S(GPRS_SNS_ST_SIZE),
561 .name = "UNCONFIGURED",
562 .action = gprs_sns_st_unconfigured,
563 },
564 [GPRS_SNS_ST_SIZE] = {
565 .in_event_mask = S(GPRS_SNS_EV_SIZE_ACK),
566 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
567 S(GPRS_SNS_ST_SIZE) |
568 S(GPRS_SNS_ST_CONFIG_BSS),
569 .name = "SIZE",
570 .action = gprs_sns_st_size,
571 .onenter = gprs_sns_st_size_onenter,
572 },
573 [GPRS_SNS_ST_CONFIG_BSS] = {
574 .in_event_mask = S(GPRS_SNS_EV_CONFIG_ACK),
575 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
576 S(GPRS_SNS_ST_CONFIG_BSS) |
577 S(GPRS_SNS_ST_CONFIG_SGSN),
578 .name = "CONFIG_BSS",
579 .action = gprs_sns_st_config_bss,
580 .onenter = gprs_sns_st_config_bss_onenter,
581 },
582 [GPRS_SNS_ST_CONFIG_SGSN] = {
583 .in_event_mask = S(GPRS_SNS_EV_CONFIG) |
584 S(GPRS_SNS_EV_CONFIG_END),
585 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
586 S(GPRS_SNS_ST_CONFIG_SGSN) |
587 S(GPRS_SNS_ST_CONFIGURED),
588 .name = "CONFIG_SGSN",
589 .action = gprs_sns_st_config_sgsn,
590 },
591 [GPRS_SNS_ST_CONFIGURED] = {
592 .in_event_mask = S(GPRS_SNS_EV_ADD) |
593 S(GPRS_SNS_EV_DELETE) |
594 S(GPRS_SNS_EV_CHANGE_WEIGHT),
595 .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED),
596 .name = "CONFIGURED",
597 .action = gprs_sns_st_configured,
598 .onenter = gprs_sns_st_configured_onenter,
599 },
600};
601
602static int gprs_sns_fsm_bss_timer_cb(struct osmo_fsm_inst *fi)
603{
604 struct gprs_ns_inst *nsi = ns_inst_from_fi(fi);
605
606 switch (fi->T) {
607 case 1:
608 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SIZE, nsi->timeout[NS_TOUT_TSNS_PROV], 1);
609 break;
610 case 2:
611 osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_BSS, nsi->timeout[NS_TOUT_TSNS_PROV], 2);
612 break;
613 }
614 return 0;
615}
616
617static struct osmo_fsm gprs_sns_bss_fsm = {
618 .name = "GPRS-SNS-BSS",
619 .states = gprs_sns_bss_states,
620 .num_states = ARRAY_SIZE(gprs_sns_bss_states),
621 .allstate_event_mask = 0,
622 .allstate_action = NULL,
623 .cleanup = NULL,
624 .timer_cb = gprs_sns_fsm_bss_timer_cb,
625 /* .log_subsys = DNS, "is not constant" */
626 .event_names = gprs_sns_event_names,
627 .pre_term = NULL,
628};
629
630struct osmo_fsm_inst *gprs_sns_bss_fsm_alloc(void *ctx, struct gprs_nsvc *nsvc,
631 const char *id)
632{
633 struct osmo_fsm_inst *fi;
634 struct gprs_sns_state *gss;
635 struct gprs_ns_ie_ip4_elem *ip4;
636 struct gprs_ns_inst *nsi = nsvc->nsi;
637
638 fi = osmo_fsm_inst_alloc(&gprs_sns_bss_fsm, ctx, NULL, LOGL_DEBUG, id);
639 if (!fi)
640 return fi;
641
642 gss = talloc_zero(fi, struct gprs_sns_state);
643 if (!gss)
644 goto err;
645
646 fi->priv = gss;
647 gss->nsi = nsi;
648 /* FIXME: we shouldn't use 'nsvc' here but only gprs_ns_inst */
649 gss->nsvc_hack = nsvc;
650 gss->next_nsvci = 65533; /* 65534 + 65535 are already used internally */
651
652 /* create IPv4 list from the one IP/port the NS instance has */
653 ip4 = talloc_zero(gss, struct gprs_ns_ie_ip4_elem);
654 if (!ip4)
655 goto err;
656 if (nsi->nsip.local_ip)
657 ip4->ip_addr = htonl(nsi->nsip.local_ip);
658 else {
659 /* unspecified local address. Figure out which address the kernel would use if we
660 * wanted to send a packet to the remote_ip */
661 char local_ip[32];
Harald Welte24e67f82019-03-16 18:06:22 +0100662 struct sockaddr_in *daddr = &nsvc->ip.bts_addr;
663 osmo_sock_local_ip(local_ip, inet_ntoa(daddr->sin_addr));
Harald Welte047f3872018-07-01 21:04:45 +0200664 ip4->ip_addr = inet_addr(local_ip);
665 }
666 ip4->udp_port = htons(gss->nsi->nsip.local_port);
667 ip4->sig_weight = 2;
668 ip4->data_weight = 1;
669 gss->ip4_local = ip4;
670 gss->num_ip4_local = 1;
671 gss->num_max_nsvcs = 8;
672 gss->num_max_ip4_remote = 4;
673
674 return fi;
675err:
676 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
677 return NULL;
678}
679
680int gprs_sns_bss_fsm_start(struct gprs_ns_inst *nsi)
681{
682 return osmo_fsm_inst_dispatch(nsi->bss_sns_fi, GPRS_SNS_EV_START, NULL);
683}
684
685/* main entry point for receiving SNS messages from the network */
686int gprs_ns_rx_sns(struct gprs_ns_inst *nsi, struct msgb *msg, struct tlv_parsed *tp)
687{
688 struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h;
689 uint16_t nsei = msgb_nsei(msg);
690 struct osmo_fsm_inst *fi;
691
692 LOGP(DNS, LOGL_DEBUG, "NSEI=%u Rx SNS PDU type %s\n", nsei,
693 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
694
695 /* FIXME: how to resolve SNS FSM Instance by NSEI (SGSN)? */
696 fi = nsi->bss_sns_fi;
697
698 switch (nsh->pdu_type) {
699 case SNS_PDUT_SIZE:
700 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE, tp);
701 break;
702 case SNS_PDUT_SIZE_ACK:
703 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_SIZE_ACK, tp);
704 break;
705 case SNS_PDUT_CONFIG:
706 if (nsh->data[0] & 0x01)
707 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_END, tp);
708 else
709 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG, tp);
710 break;
711 case SNS_PDUT_CONFIG_ACK:
712 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CONFIG_ACK, tp);
713 break;
714 case SNS_PDUT_ADD:
715 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_ADD, tp);
716 break;
717 case SNS_PDUT_DELETE:
718 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_DELETE, tp);
719 break;
720 case SNS_PDUT_CHANGE_WEIGHT:
721 osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_CHANGE_WEIGHT, tp);
722 break;
723 case SNS_PDUT_ACK:
724 LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
725 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
726 break;
727 default:
728 LOGP(DNS, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
729 get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
730 return -EINVAL;
731 }
732
733 return 0;
734}
735
736int gprs_sns_init(void)
737{
738 /* "DNS" is not a constant/#define, but an integer variable set by the client app */
739 gprs_sns_bss_fsm.log_subsys = DNS;
740 return osmo_fsm_register(&gprs_sns_bss_fsm);
741}
742
743#include <osmocom/vty/vty.h>
744#include <osmocom/vty/misc.h>
745
746static void vty_dump_sns_ip4(struct vty *vty, const struct gprs_ns_ie_ip4_elem *ip4)
747{
748 struct in_addr in = { .s_addr = ip4->ip_addr };
749 vty_out(vty, " %s:%u, Signalling Weight: %u, Data Weight: %u%s",
750 inet_ntoa(in), ntohs(ip4->udp_port), ip4->sig_weight, ip4->data_weight, VTY_NEWLINE);
751}
752
753void gprs_sns_dump_vty(struct vty *vty, const struct gprs_ns_inst *nsi, bool stats)
754{
755 struct gprs_sns_state *gss;
756 unsigned int i;
757
758 if (!nsi->bss_sns_fi)
759 return;
760
761 vty_out_fsm_inst(vty, nsi->bss_sns_fi);
762 gss = (struct gprs_sns_state *) nsi->bss_sns_fi->priv;
763
764 vty_out(vty, "Maximum number of remote NS-VCs: %zu, IPv4 Endpoints: %zu%s",
765 gss->num_max_nsvcs, gss->num_max_ip4_remote, VTY_NEWLINE);
766
767 vty_out(vty, "Local IPv4 Endpoints:%s", VTY_NEWLINE);
768 for (i = 0; i < gss->num_ip4_local; i++)
769 vty_dump_sns_ip4(vty, &gss->ip4_local[i]);
770
771 vty_out(vty, "Remote IPv4 Endpoints:%s", VTY_NEWLINE);
772 for (i = 0; i < gss->num_ip4_remote; i++)
773 vty_dump_sns_ip4(vty, &gss->ip4_remote[i]);
774}