2020-07-12 11:45:50 +00:00
|
|
|
/*! \file gprs_ns2_internal.h */
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#include <osmocom/gprs/protocol/gsm_08_16.h>
|
|
|
|
#include <osmocom/gprs/gprs_ns2.h>
|
|
|
|
|
2021-01-20 13:54:14 +00:00
|
|
|
#define LOGNSE(nse, lvl, fmt, args ...) \
|
|
|
|
LOGP(DLNS, lvl, "NSE(%05u) " fmt, (nse)->nsei, ## args)
|
|
|
|
|
|
|
|
#define LOGBIND(bind, lvl, fmt, args ...) \
|
|
|
|
LOGP(DLNS, lvl, "BIND(%s) " fmt, (bind)->name, ## args)
|
|
|
|
|
|
|
|
|
|
|
|
#define LOGNSVC(nsvc, lvl, fmt, args ...) \
|
|
|
|
do { \
|
|
|
|
if ((nsvc)->nsvci_is_valid) { \
|
|
|
|
LOGP(DLNS, lvl, "NSE(%05u)-NSVC(%05u) " fmt, \
|
|
|
|
(nsvc)->nse->nsei, (nsvc)->nsvci, ## args); \
|
|
|
|
} else { \
|
|
|
|
LOGP(DLNS, lvl, "NSE(%05u)-NSVC(none) " fmt, \
|
|
|
|
(nsvc)->nse->nsei, ## args); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2020-07-12 11:45:50 +00:00
|
|
|
struct osmo_fsm_inst;
|
|
|
|
struct tlv_parsed;
|
|
|
|
struct vty;
|
|
|
|
|
|
|
|
struct gprs_ns2_vc_driver;
|
|
|
|
struct gprs_ns2_vc_bind;
|
|
|
|
|
2020-12-07 05:18:32 +00:00
|
|
|
#define NS_TIMERS_COUNT 10
|
2020-12-16 11:02:51 +00:00
|
|
|
#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov|tsns-size-retries|tsns-config-retries)"
|
2020-07-12 11:45:50 +00:00
|
|
|
#define NS_TIMERS_HELP \
|
|
|
|
"(un)blocking Timer (Tns-block) timeout\n" \
|
|
|
|
"(un)blocking Timer (Tns-block) number of retries\n" \
|
|
|
|
"Reset Timer (Tns-reset) timeout\n" \
|
|
|
|
"Reset Timer (Tns-reset) number of retries\n" \
|
|
|
|
"Test Timer (Tns-test) timeout\n" \
|
|
|
|
"Alive Timer (Tns-alive) timeout\n" \
|
|
|
|
"Alive Timer (Tns-alive) number of retries\n" \
|
2020-12-07 05:18:32 +00:00
|
|
|
"SNS Provision Timer (Tsns-prov) timeout\n" \
|
|
|
|
"SNS Size number of retries\n" \
|
|
|
|
"SNS Config number of retries\n" \
|
2020-07-12 11:45:50 +00:00
|
|
|
|
|
|
|
/* Educated guess - LLC user payload is 1500 bytes plus possible headers */
|
|
|
|
#define NS_ALLOC_SIZE 3072
|
|
|
|
#define NS_ALLOC_HEADROOM 20
|
|
|
|
|
|
|
|
enum ns2_timeout {
|
|
|
|
NS_TOUT_TNS_BLOCK,
|
|
|
|
NS_TOUT_TNS_BLOCK_RETRIES,
|
|
|
|
NS_TOUT_TNS_RESET,
|
|
|
|
NS_TOUT_TNS_RESET_RETRIES,
|
|
|
|
NS_TOUT_TNS_TEST,
|
|
|
|
NS_TOUT_TNS_ALIVE,
|
|
|
|
NS_TOUT_TNS_ALIVE_RETRIES,
|
|
|
|
NS_TOUT_TSNS_PROV,
|
2020-12-07 05:18:32 +00:00
|
|
|
NS_TOUT_TSNS_SIZE_RETRIES,
|
|
|
|
NS_TOUT_TSNS_CONFIG_RETRIES,
|
2020-07-12 11:45:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum nsvc_timer_mode {
|
|
|
|
/* standard timers */
|
|
|
|
NSVC_TIMER_TNS_TEST,
|
|
|
|
NSVC_TIMER_TNS_ALIVE,
|
|
|
|
NSVC_TIMER_TNS_RESET,
|
|
|
|
_NSVC_TIMER_NR,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum ns_stat {
|
|
|
|
NS_STAT_ALIVE_DELAY,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*! Osmocom NS2 VC create status */
|
|
|
|
enum gprs_ns2_cs {
|
|
|
|
GPRS_NS2_CS_CREATED, /*!< A NSVC object has been created */
|
|
|
|
GPRS_NS2_CS_FOUND, /*!< A NSVC object has been found */
|
|
|
|
GPRS_NS2_CS_REJECTED, /*!< Rejected and answered message */
|
|
|
|
GPRS_NS2_CS_SKIPPED, /*!< Skipped message */
|
|
|
|
GPRS_NS2_CS_ERROR, /*!< Failed to process message */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#define NSE_S_BLOCKED 0x0001
|
|
|
|
#define NSE_S_ALIVE 0x0002
|
|
|
|
#define NSE_S_RESET 0x0004
|
|
|
|
|
|
|
|
#define NS_DESC_B(st) ((st) & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED")
|
|
|
|
#define NS_DESC_A(st) ((st) & NSE_S_ALIVE ? "ALIVE" : "DEAD")
|
|
|
|
#define NS_DESC_R(st) ((st) & NSE_S_RESET ? "RESET" : "UNRESET")
|
|
|
|
|
|
|
|
/*! An instance of the NS protocol stack */
|
|
|
|
struct gprs_ns2_inst {
|
|
|
|
/*! callback to the user for incoming UNIT DATA IND */
|
|
|
|
osmo_prim_cb cb;
|
|
|
|
|
|
|
|
/*! callback data */
|
|
|
|
void *cb_data;
|
|
|
|
|
|
|
|
/*! linked lists of all NSVC binds (e.g. IPv4 bind, but could be also E1 */
|
|
|
|
struct llist_head binding;
|
|
|
|
|
|
|
|
/*! linked lists of all NSVC in this instance */
|
|
|
|
struct llist_head nse;
|
|
|
|
|
|
|
|
/*! create dynamic NSE on receiving packages */
|
|
|
|
bool create_nse;
|
|
|
|
|
|
|
|
uint16_t timeout[NS_TIMERS_COUNT];
|
|
|
|
|
|
|
|
/*! workaround for rate counter until rate counter accepts char str as index */
|
|
|
|
uint32_t rate_ctr_idx;
|
2020-12-01 21:21:14 +00:00
|
|
|
|
|
|
|
/*! libmnl netlink socket for link state monitoring */
|
|
|
|
struct osmo_mnl *linkmon_mnl;
|
2020-07-12 11:45:50 +00:00
|
|
|
};
|
|
|
|
|
2020-12-01 21:21:14 +00:00
|
|
|
|
2020-07-12 11:45:50 +00:00
|
|
|
/*! Structure repesenting a NSE. The BSS/PCU will only have a single NSE, while SGSN has one for each BSS/PCU */
|
|
|
|
struct gprs_ns2_nse {
|
|
|
|
uint16_t nsei;
|
|
|
|
|
|
|
|
/*! entry back to ns2_inst */
|
|
|
|
struct gprs_ns2_inst *nsi;
|
|
|
|
|
|
|
|
/*! llist entry for gprs_ns2_inst */
|
|
|
|
struct llist_head list;
|
|
|
|
|
|
|
|
/*! llist head to hold all nsvc */
|
|
|
|
struct llist_head nsvc;
|
|
|
|
|
2020-12-26 17:00:17 +00:00
|
|
|
/*! count all active NSVCs */
|
|
|
|
int nsvc_count;
|
2020-11-18 23:41:47 +00:00
|
|
|
|
2020-07-12 11:45:50 +00:00
|
|
|
/*! true if this NSE was created by VTY or pcu socket) */
|
|
|
|
bool persistent;
|
|
|
|
|
2020-10-01 21:24:07 +00:00
|
|
|
/*! true if this NSE wasn't yet alive at all.
|
|
|
|
* Will be true after the first status ind with NS_AFF_CAUSE_RECOVERY */
|
|
|
|
bool first;
|
|
|
|
|
2020-07-12 11:45:50 +00:00
|
|
|
/*! true if this NSE has at least one alive VC */
|
|
|
|
bool alive;
|
|
|
|
|
2020-11-19 01:44:04 +00:00
|
|
|
/*! which link-layer are we based on? */
|
|
|
|
enum gprs_ns2_ll ll;
|
|
|
|
|
2020-12-01 00:03:52 +00:00
|
|
|
/*! which dialect does this NSE speaks? */
|
|
|
|
enum gprs_ns2_dialect dialect;
|
|
|
|
|
2020-07-12 11:45:50 +00:00
|
|
|
struct osmo_fsm_inst *bss_sns_fi;
|
2021-01-18 13:58:51 +00:00
|
|
|
|
|
|
|
/*! sum of all the data weight of _active_ NS-VCs */
|
|
|
|
uint32_t sum_data_weight;
|
|
|
|
|
|
|
|
/*! sum of all the signalling weight of _active_ NS-VCs */
|
|
|
|
uint32_t sum_sig_weight;
|
2020-07-12 11:45:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*! Structure representing a single NS-VC */
|
|
|
|
struct gprs_ns2_vc {
|
|
|
|
/*! list of NS-VCs within NSE */
|
|
|
|
struct llist_head list;
|
|
|
|
|
|
|
|
/*! list of NS-VCs within bind, bind is the owner! */
|
|
|
|
struct llist_head blist;
|
|
|
|
|
|
|
|
/*! pointer to NS Instance */
|
|
|
|
struct gprs_ns2_nse *nse;
|
|
|
|
|
|
|
|
/*! pointer to NS VL bind. bind own the memory of this instance */
|
|
|
|
struct gprs_ns2_vc_bind *bind;
|
|
|
|
|
|
|
|
/*! true if this NS was created by VTY or pcu socket) */
|
|
|
|
bool persistent;
|
|
|
|
|
|
|
|
/*! uniquely identifies NS-VC if VC contains nsvci */
|
|
|
|
uint16_t nsvci;
|
|
|
|
|
|
|
|
/*! signalling weight. 0 = don't use for signalling (BVCI == 0)*/
|
|
|
|
uint8_t sig_weight;
|
|
|
|
|
2020-11-18 23:41:47 +00:00
|
|
|
/*! signalling packet counter for the load sharing function */
|
|
|
|
uint8_t sig_counter;
|
|
|
|
|
|
|
|
/*! data weight. 0 = don't use for user data (BVCI != 0) */
|
2020-07-12 11:45:50 +00:00
|
|
|
uint8_t data_weight;
|
|
|
|
|
|
|
|
/*! can be used by the bind/driver of the virtual circuit. e.g. ipv4/ipv6/frgre/e1 */
|
|
|
|
void *priv;
|
|
|
|
|
|
|
|
bool nsvci_is_valid;
|
|
|
|
bool sns_only;
|
|
|
|
|
|
|
|
struct rate_ctr_group *ctrg;
|
|
|
|
struct osmo_stat_item_group *statg;
|
|
|
|
|
|
|
|
enum gprs_ns2_vc_mode mode;
|
|
|
|
|
|
|
|
struct osmo_fsm_inst *fi;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*! Structure repesenting a bind instance. E.g. IPv4 listen port. */
|
|
|
|
struct gprs_ns2_vc_bind {
|
2020-12-03 05:02:03 +00:00
|
|
|
/*! unique name */
|
|
|
|
const char *name;
|
2020-07-12 11:45:50 +00:00
|
|
|
/*! list entry in nsi */
|
|
|
|
struct llist_head list;
|
|
|
|
/*! list of all VC */
|
|
|
|
struct llist_head nsvc;
|
|
|
|
/*! driver private structure */
|
|
|
|
void *priv;
|
|
|
|
/*! a pointer back to the nsi */
|
|
|
|
struct gprs_ns2_inst *nsi;
|
|
|
|
struct gprs_ns2_vc_driver *driver;
|
|
|
|
|
2020-12-01 00:03:52 +00:00
|
|
|
bool accept_ipaccess;
|
|
|
|
bool accept_sns;
|
2020-07-12 11:45:50 +00:00
|
|
|
|
2020-12-17 05:58:53 +00:00
|
|
|
/*! transfer capability in mbit */
|
|
|
|
int transfer_capability;
|
|
|
|
|
2020-11-19 01:44:04 +00:00
|
|
|
/*! which link-layer are we based on? */
|
|
|
|
enum gprs_ns2_ll ll;
|
|
|
|
|
2020-07-12 11:45:50 +00:00
|
|
|
/*! send a msg over a VC */
|
|
|
|
int (*send_vc)(struct gprs_ns2_vc *nsvc, struct msgb *msg);
|
|
|
|
|
|
|
|
/*! free the vc priv data */
|
|
|
|
void (*free_vc)(struct gprs_ns2_vc *nsvc);
|
|
|
|
|
2020-10-02 00:34:39 +00:00
|
|
|
/*! allow to show information for the vty */
|
|
|
|
void (*dump_vty)(const struct gprs_ns2_vc_bind *bind,
|
|
|
|
struct vty *vty, bool stats);
|
|
|
|
};
|
2020-07-12 11:45:50 +00:00
|
|
|
|
|
|
|
struct gprs_ns2_vc_driver {
|
|
|
|
const char *name;
|
|
|
|
void *priv;
|
|
|
|
void (*free_bind)(struct gprs_ns2_vc_bind *driver);
|
|
|
|
};
|
|
|
|
|
|
|
|
enum gprs_ns2_cs ns2_create_vc(struct gprs_ns2_vc_bind *bind,
|
|
|
|
struct msgb *msg,
|
|
|
|
const char *logname,
|
|
|
|
struct msgb **reject,
|
|
|
|
struct gprs_ns2_vc **success);
|
|
|
|
|
2020-09-23 22:47:17 +00:00
|
|
|
int ns2_recv_vc(struct gprs_ns2_vc *nsvc,
|
2020-07-12 11:45:50 +00:00
|
|
|
struct msgb *msg);
|
|
|
|
|
|
|
|
struct gprs_ns2_vc *ns2_vc_alloc(struct gprs_ns2_vc_bind *bind,
|
|
|
|
struct gprs_ns2_nse *nse,
|
2020-12-01 00:03:52 +00:00
|
|
|
bool initiater,
|
2020-11-29 16:39:19 +00:00
|
|
|
enum gprs_ns2_vc_mode vc_mode,
|
|
|
|
const char *id);
|
2020-07-12 11:45:50 +00:00
|
|
|
|
|
|
|
struct msgb *gprs_ns2_msgb_alloc(void);
|
|
|
|
|
2020-11-19 04:24:37 +00:00
|
|
|
void gprs_ns2_sns_write_vty(struct vty *vty, const struct gprs_ns2_nse *nse);
|
ns2: Properly indent VTY output
If multiple objects are printed in the VTY, only the first line of each
object should be on the first character of the line, all others should
be indented. With this patch the "snow ns entities" output becomes
much more readable:
OsmoGbProxy> show ns entities
NSEI 00102: UDP, DEAD
FSM Instance Name: 'GPRS-NS2-SNS-BSS(NSE00102-SNS)[0x6120000018a0]', ID: 'NSE00102-SNS'
Log-Level: 'DEBUG', State: 'SIZE'
Timer: 1
Maximum number of remote NS-VCs: 8, IPv4 Endpoints: 4, IPv6 Endpoints: 0
NSVCI none: UNCONFIGURED DYNAMIC data_weight=1 sig_weight=1 udp)[127.0.0.1]:23000<>[127.0.0.11]:8888
NSEI 00101: UDP, DEAD
FSM Instance Name: 'GPRS-NS2-SNS-BSS(NSE00101-SNS)[0x6120000015a0]', ID: 'NSE00101-SNS'
Log-Level: 'DEBUG', State: 'SIZE'
Timer: 1
Maximum number of remote NS-VCs: 8, IPv4 Endpoints: 4, IPv6 Endpoints: 0
NSVCI none: UNCONFIGURED DYNAMIC data_weight=1 sig_weight=1 udp)[127.0.0.1]:23000<>[127.0.0.10]:7777
Change-Id: Id1b4c80a6caef410076a68b4301adaa01ba7e57a
2021-01-19 19:58:33 +00:00
|
|
|
void gprs_ns2_sns_dump_vty(struct vty *vty, const char *prefix, const struct gprs_ns2_nse *nse, bool stats);
|
2020-10-01 20:56:03 +00:00
|
|
|
void ns2_prim_status_ind(struct gprs_ns2_nse *nse,
|
2020-11-03 22:05:43 +00:00
|
|
|
struct gprs_ns2_vc *nsvc,
|
2020-10-01 20:56:03 +00:00
|
|
|
uint16_t bvci,
|
2020-07-12 11:45:50 +00:00
|
|
|
enum gprs_ns2_affecting_cause cause);
|
|
|
|
void ns2_nse_notify_alive(struct gprs_ns2_vc *nsvc, bool alive);
|
|
|
|
|
|
|
|
/* message */
|
|
|
|
int gprs_ns2_validate(struct gprs_ns2_vc *nsvc,
|
|
|
|
uint8_t pdu_type,
|
|
|
|
struct msgb *msg,
|
|
|
|
struct tlv_parsed *tp,
|
|
|
|
uint8_t *cause);
|
|
|
|
|
|
|
|
/* SNS messages */
|
|
|
|
int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
|
|
|
|
const struct gprs_ns_ie_ip4_elem *ip4_elems,
|
|
|
|
unsigned int num_ip4_elems,
|
|
|
|
const struct gprs_ns_ie_ip6_elem *ip6_elems,
|
|
|
|
unsigned int num_ip6_elems);
|
|
|
|
int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
|
|
|
|
const struct gprs_ns_ie_ip4_elem *ip4_elems,
|
|
|
|
unsigned int num_ip4_elems,
|
|
|
|
const struct gprs_ns_ie_ip6_elem *ip6_elems,
|
|
|
|
unsigned int num_ip6_elems);
|
|
|
|
int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause);
|
|
|
|
int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,
|
|
|
|
int ip4_ep_nr, int ip6_ep_nr);
|
|
|
|
int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause);
|
|
|
|
|
|
|
|
/* transmit message over a VC */
|
|
|
|
int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause);
|
|
|
|
int ns2_tx_block_ack(struct gprs_ns2_vc *nsvc);
|
|
|
|
|
|
|
|
int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause);
|
|
|
|
int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc);
|
|
|
|
|
|
|
|
int ns2_tx_unblock(struct gprs_ns2_vc *nsvc);
|
|
|
|
int ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc);
|
|
|
|
|
|
|
|
int ns2_tx_alive(struct gprs_ns2_vc *nsvc);
|
|
|
|
int ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc);
|
|
|
|
|
|
|
|
int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
|
|
|
|
uint16_t bvci, uint8_t sducontrol,
|
|
|
|
struct msgb *msg);
|
|
|
|
|
|
|
|
int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
|
|
|
|
uint16_t bvci, struct msgb *orig_msg);
|
|
|
|
|
|
|
|
/* driver */
|
|
|
|
struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,
|
|
|
|
struct gprs_ns2_nse *nse,
|
2020-10-09 14:47:01 +00:00
|
|
|
const struct osmo_sockaddr *remote);
|
2020-12-07 06:37:07 +00:00
|
|
|
int ns2_ip_count_bind(struct gprs_ns2_inst *nsi, struct osmo_sockaddr *remote);
|
|
|
|
struct gprs_ns2_vc_bind *ns2_ip_get_bind_by_index(struct gprs_ns2_inst *nsi,
|
|
|
|
struct osmo_sockaddr *remote,
|
|
|
|
int index);
|
2020-07-12 11:45:50 +00:00
|
|
|
|
|
|
|
/* sns */
|
|
|
|
int gprs_ns2_sns_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp);
|
|
|
|
struct osmo_fsm_inst *ns2_sns_bss_fsm_alloc(struct gprs_ns2_nse *nse,
|
|
|
|
const char *id);
|
|
|
|
void ns2_sns_free_nsvc(struct gprs_ns2_vc *nsvc);
|
|
|
|
|
|
|
|
/* vc */
|
|
|
|
struct osmo_fsm_inst *gprs_ns2_vc_fsm_alloc(struct gprs_ns2_vc *nsvc,
|
|
|
|
const char *id, bool initiate);
|
|
|
|
int gprs_ns2_vc_fsm_start(struct gprs_ns2_vc *nsvc);
|
2020-11-18 13:08:07 +00:00
|
|
|
int gprs_ns2_vc_force_unconfigured(struct gprs_ns2_vc *nsvc);
|
2020-07-12 11:45:50 +00:00
|
|
|
int gprs_ns2_vc_rx(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp);
|
|
|
|
int gprs_ns2_vc_is_alive(struct gprs_ns2_vc *nsvc);
|
|
|
|
int gprs_ns2_vc_is_unblocked(struct gprs_ns2_vc *nsvc);
|
2021-01-17 19:12:46 +00:00
|
|
|
int ns2_vc_block(struct gprs_ns2_vc *nsvc);
|
|
|
|
int ns2_vc_unblock(struct gprs_ns2_vc *nsvc);
|
2020-07-12 11:45:50 +00:00
|
|
|
|
|
|
|
/* nse */
|
|
|
|
void ns2_nse_notify_unblocked(struct gprs_ns2_vc *nsvc, bool unblocked);
|
2020-12-01 00:03:52 +00:00
|
|
|
enum gprs_ns2_vc_mode gprs_ns2_dialect_to_vc_mode(enum gprs_ns2_dialect dialect);
|
2020-12-17 05:58:53 +00:00
|
|
|
int ns2_count_transfer_cap(struct gprs_ns2_nse *nse,
|
|
|
|
uint16_t bvci);
|