| #ifndef _GPRS_NS_H |
| #define _GPRS_NS_H |
| |
| #include <stdint.h> |
| |
| /* GPRS Networks Service (NS) messages on the Gb interface |
| * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) |
| * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */ |
| |
| struct gprs_ns_hdr { |
| uint8_t pdu_type; |
| uint8_t data[0]; |
| } __attribute__((packed)); |
| |
| /* TS 08.16, Section 10.3.7, Table 14 */ |
| enum ns_pdu_type { |
| NS_PDUT_UNITDATA = 0x00, |
| NS_PDUT_RESET = 0x02, |
| NS_PDUT_RESET_ACK = 0x03, |
| NS_PDUT_BLOCK = 0x04, |
| NS_PDUT_BLOCK_ACK = 0x05, |
| NS_PDUT_UNBLOCK = 0x06, |
| NS_PDUT_UNBLOCK_ACK = 0x07, |
| NS_PDUT_STATUS = 0x08, |
| NS_PDUT_ALIVE = 0x0a, |
| NS_PDUT_ALIVE_ACK = 0x0b, |
| /* TS 48.016 Section 10.3.7, Table 10.3.7.1 */ |
| SNS_PDUT_ACK = 0x0c, |
| SNS_PDUT_ADD = 0x0d, |
| SNS_PDUT_CHANGE_WEIGHT = 0x0e, |
| SNS_PDUT_CONFIG = 0x0f, |
| SNS_PDUT_CONFIG_ACK = 0x10, |
| SNS_PDUT_DELETE = 0x11, |
| SNS_PDUT_SIZE = 0x12, |
| SNS_PDUT_SIZE_ACK = 0x13, |
| }; |
| |
| /* TS 08.16, Section 10.3, Table 12 */ |
| enum ns_ctrl_ie { |
| NS_IE_CAUSE = 0x00, |
| NS_IE_VCI = 0x01, |
| NS_IE_PDU = 0x02, |
| NS_IE_BVCI = 0x03, |
| NS_IE_NSEI = 0x04, |
| /* TS 48.016 Section 10.3, Table 10.3.1 */ |
| NS_IE_IPv4_LIST = 0x05, |
| NS_IE_IPv6_LIST = 0x06, |
| NS_IE_MAX_NR_NSVC = 0x07, |
| NS_IE_IPv4_EP_NR = 0x08, |
| NS_IE_IPv6_EP_NR = 0x09, |
| NS_IE_RESET_FLAG = 0x0a, |
| NS_IE_IP_ADDR = 0x0b, |
| }; |
| |
| /* TS 08.16, Section 10.3.2, Table 13 */ |
| enum ns_cause { |
| NS_CAUSE_TRANSIT_FAIL = 0x00, |
| NS_CAUSE_OM_INTERVENTION = 0x01, |
| NS_CAUSE_EQUIP_FAIL = 0x02, |
| NS_CAUSE_NSVC_BLOCKED = 0x03, |
| NS_CAUSE_NSVC_UNKNOWN = 0x04, |
| NS_CAUSE_BVCI_UNKNOWN = 0x05, |
| NS_CAUSE_SEM_INCORR_PDU = 0x08, |
| NS_CAUSE_PDU_INCOMP_PSTATE = 0x0a, |
| NS_CAUSE_PROTO_ERR_UNSPEC = 0x0b, |
| NS_CAUSE_INVAL_ESSENT_IE = 0x0c, |
| NS_CAUSE_MISSING_ESSENT_IE = 0x0d, |
| /* TS 48.016 Section 10.3.2, Table 10.3.2.1 */ |
| NS_CAUSE_INVAL_NR_IPv4_EP = 0x0e, |
| NS_CAUSE_INVAL_NR_IPv6_EP = 0x0f, |
| NS_CAUSE_INVAL_NR_NS_VC = 0x10, |
| NS_CAUSE_INVAL_WEIGH = 0x11, |
| NS_CAUSE_UNKN_IP_EP = 0x12, |
| NS_CAUSE_UNKN_IP_ADDR = 0x13, |
| NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14, |
| }; |
| |
| /* Our Implementation */ |
| #include <netinet/in.h> |
| #include <osmocore/linuxlist.h> |
| #include <osmocore/msgb.h> |
| #include <osmocore/timer.h> |
| #include <osmocore/select.h> |
| |
| #define NS_TIMERS_COUNT 7 |
| #define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)" |
| #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" \ |
| |
| enum ns_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, |
| }; |
| |
| #define NSE_S_BLOCKED 0x0001 |
| #define NSE_S_ALIVE 0x0002 |
| |
| enum gprs_ns_ll { |
| GPRS_NS_LL_UDP, |
| GPRS_NS_LL_E1, |
| GPRS_NS_LL_FR_GRE, |
| }; |
| |
| enum gprs_ns_evt { |
| GPRS_NS_EVT_UNIT_DATA, |
| }; |
| |
| struct gprs_nsvc; |
| typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, |
| struct msgb *msg, uint16_t bvci); |
| |
| /* An instance of the NS protocol stack */ |
| struct gprs_ns_inst { |
| /* callback to the user for incoming UNIT DATA IND */ |
| gprs_ns_cb_t *cb; |
| |
| /* linked lists of all NSVC in this instance */ |
| struct llist_head gprs_nsvcs; |
| |
| /* a NSVC object that's needed to deal with packets for unknown NSVC */ |
| struct gprs_nsvc *unknown_nsvc; |
| |
| uint16_t timeout[NS_TIMERS_COUNT]; |
| |
| /* NS-over-IP specific bits */ |
| struct { |
| struct bsc_fd fd; |
| uint32_t local_ip; |
| uint16_t local_port; |
| } nsip; |
| /* NS-over-FR-over-GRE-over-IP specific bits */ |
| struct { |
| struct bsc_fd fd; |
| uint32_t local_ip; |
| int enabled:1; |
| } frgre; |
| }; |
| |
| enum nsvc_timer_mode { |
| /* standard timers */ |
| NSVC_TIMER_TNS_TEST, |
| NSVC_TIMER_TNS_ALIVE, |
| NSVC_TIMER_TNS_RESET, |
| _NSVC_TIMER_NR, |
| }; |
| |
| struct gprs_nsvc { |
| struct llist_head list; |
| struct gprs_ns_inst *nsi; |
| |
| uint16_t nsei; /* end-to-end significance */ |
| uint16_t nsvci; /* uniquely identifies NS-VC at SGSN */ |
| |
| uint32_t state; |
| uint32_t remote_state; |
| |
| struct timer_list timer; |
| enum nsvc_timer_mode timer_mode; |
| int alive_retries; |
| |
| unsigned int remote_end_is_sgsn:1; |
| unsigned int persistent:1; |
| |
| struct rate_ctr_group *ctrg; |
| |
| /* which link-layer are we based on? */ |
| enum gprs_ns_ll ll; |
| |
| union { |
| struct { |
| struct sockaddr_in bts_addr; |
| } ip; |
| struct { |
| struct sockaddr_in bts_addr; |
| } frgre; |
| }; |
| }; |
| |
| /* Create a new NS protocol instance */ |
| struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb); |
| |
| /* Destroy a NS protocol instance */ |
| void gprs_ns_destroy(struct gprs_ns_inst *nsi); |
| |
| /* Listen for incoming GPRS packets via NS/UDP */ |
| int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi); |
| |
| struct sockaddr_in; |
| |
| /* main function for higher layers (BSSGP) to send NS messages */ |
| int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg); |
| |
| int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause); |
| int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause); |
| int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc); |
| |
| /* Listen for incoming GPRS packets via NS/FR/GRE */ |
| int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi); |
| |
| /* Establish a connection (from the BSS) to the SGSN */ |
| struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, |
| struct sockaddr_in *dest, uint16_t nsei, |
| uint16_t nsvci); |
| |
| struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci); |
| void nsvc_delete(struct gprs_nsvc *nsvc); |
| struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei); |
| struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci); |
| |
| /* Initiate a RESET procedure (including timer start, ...)*/ |
| void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause); |
| |
| /* Add NS-specific VTY stuff */ |
| int gprs_ns_vty_init(struct gprs_ns_inst *nsi); |
| |
| #define NS_ALLOC_SIZE 2048 |
| #define NS_ALLOC_HEADROOM 20 |
| static inline struct msgb *gprs_ns_msgb_alloc(void) |
| { |
| return msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM, "GPRS/NS"); |
| } |
| |
| #endif |