aboutsummaryrefslogtreecommitdiffstats
path: root/include/openbsc/gprs_ns.h
blob: 8f28d4623d84e60465c502eaec2e0af3864303f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#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 <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/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 osmo_fd fd;
		uint32_t local_ip;
		uint16_t local_port;
	} nsip;
	/* NS-over-FR-over-GRE-over-IP specific bits */
	struct {
		struct osmo_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 osmo_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