aboutsummaryrefslogtreecommitdiffstats
path: root/src/hnbgw_hnbap.c
blob: 9db670e029792882427e223667e4e11ec46ff398 (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
233
234
235
236
237
238
239
240
241
242
243
244
245
#include <osmocom/core/msgb.h>
#include <osmocom/core/utils.h>

#include <unistd.h>
#include <errno.h>
#include <string.h>

#include "asn1helpers.h"

#include "hnbap.h"
#include "hnbgw.h"
#include "hnbap_const.h"

#define IU_MSG_NUM_IES		32
#define IU_MSG_NUM_EXT_IES	32

/* common structure of a HNBAP / RUA / RANAP message, must have identical
 * memory footprint as the other messages, such as HNBRegisterRequest */
struct iu_common_msg {
	ProtocolIE_Container_1 protocolIEs;
	BOOL protocolExtensions_option;
	ProtocolIE_Container_1 protocolExtensions;
};

/* Add an IE to a Iu message
 * \param _msg Message to which we want to add
 * \param[in] ie Information Element to be added (ffasn1c generated struct)
 * \param[in] iei Information Element Identifier
 * \param[in] type asn1_type of the IE
 * \param[in] ext should this be an extension field?
 */
int iu_msg_add_ie(void *_msg, void *ie, int iei, ASN1CType *type, int ext)
{
	struct iu_common_msg *msg = _msg;
	ProtocolIE_Field_1 *field;

	if (ext) {
		msg->protocolExtensions_option = TRUE;
		if (msg->protocolExtensions.count >= IU_MSG_NUM_EXT_IES)
			return -ERANGE;
		field = &msg->protocolExtensions.tab[msg->protocolExtensions.count++];
	} else {
		if (msg->protocolIEs.count >= IU_MSG_NUM_IES)
			return -ERANGE;
		field = &msg->protocolIEs.tab[msg->protocolIEs.count++];
	}

	field->id = iei;
	//field->criticality = FIXME;
	field->value.type = type;
	field->value.u.data = ie;

	return 0;
}



static int hnbgw_hnbap_tx(struct HNBAP_PDU *pdu)
{
	/* FIXME */
}

static int hnbgw_tx_hnb_register_acc()
{
	/* FIXME */
	/* Single required response IE: RNC-ID */
}

static int hnbgw_tx_ue_register_acc()
{
#if 0
	HNBAP_PDU pdu;
	HNBRegisterAccept hnb_reg_acc;

	hnb_reg_acc.protocol_IEs

	pdu.choice = HNBAP_PDU_successfulOutcome;
	pdu.u.successfulOutcome.procedureCode = HNBAP_PC_HNBRegister;
	pdu.u.successfulOutcome.criticality = ;
	pdu.u.successfulOutcome.value.type = asn1_type_HNBRegisterAccept;
	pdu.u.successfulOutcome.value.u.data = &hnb_reg_acc;
#endif
	/* FIXME */
	/* Single required response IE: RNC-ID */
}

/* we type-cast to ProtocolIE_Container_1, as all the containers structs have
 * the same definiition.  This is of course ugly, but I see no cleaner way.
 * Similarly, from the IEI it is clear what the type should be, but in a
 * statically typed language we can only return 'void *' and hope the caller
 * doesn the right typecast. */
#define FIND_IE(cont, id) find_ie((const struct ProtocolIE_Container_1 *)cont, id)
static void *find_ie(const struct ProtocolIE_Container_1 *cont, ProtocolIE_ID id)
{
	int i;

	/* iterate over the array of IEs in the IE container and look for the first
	 * occurrence of the right IEI */
	for (i = 0; i < cont->count; i++) {
		ProtocolIE_Field_1 *field = &cont->tab[i];
		if (field->id == id) {
			OSMO_ASSERT(field->value.type);
			/* FIXME: we shoudl check if it is the correct type, not just any type */
			return field->value.u.data;
		}
	}
	return NULL;
}

static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, struct HNBRegisterRequest *req)
{
	HNB_Identity *identity =
		FIND_IE(&req->protocolIEs, HNBAP_IEI_HNB_Identity);
	HNB_Location_Information *loc =
		FIND_IE(&req->protocolIEs, HNBAP_IEI_HNB_Location_Information);
	PLMNidentity *plmn_id =
		FIND_IE(&req->protocolIEs, HNBAP_IEI_PLMNidentity);
	CellIdentity *cell_id =
		FIND_IE(&req->protocolIEs, HNBAP_IEI_CellIdentity);
	LAC *lac = FIND_IE(&req->protocolIEs, HNBAP_IEI_LAC);
	RAC *rac = FIND_IE(&req->protocolIEs, HNBAP_IEI_RAC);
	SAC *sac = FIND_IE(&req->protocolIEs, HNBAP_IEI_SAC);
	/* Optional: CSG-ID */

	if(!identity || !loc || !plmn_id || !cell_id || !lac || !rac || !sac)
		return -1;

	/* copy all identity parameters from the message to ctx */
	asn1_strncpy(ctx->identity_info, &identity->hNB_Identity_Info,
		sizeof(ctx->identity_info));
	ctx->id.lac = asn1str_to_u16(lac);
	ctx->id.sac = asn1str_to_u16(sac);
	ctx->id.rac = asn1str_to_u8(rac);
	ctx->id.cid = asn1bitstr_to_u32(cell_id);
	//ctx->id.mcc FIXME
	//ctx->id.mnc FIXME

	DEBUGP(DMAIN, "HNB-REGISTER-REQ from %s\n", ctx->identity_info);

	/* FIXME: Send HNBRegisterAccept */
}

static int hnbgw_rx_ue_register_req(struct hnb_context *ctx, struct UERegisterRequest *req)
{
	UE_Identity *id =
		FIND_IE(&req->protocolIEs, HNBAP_IEI_UE_Identity);
	Registration_Cause *reg_cause =
		FIND_IE(&req->protocolIEs, HNBAP_IEI_RegistrationCause);
	UE_Capabilities *ue_cap =
		FIND_IE(&req->protocolIEs, HNBAP_IEI_UE_Capabilities);

	if (!id || !reg_cause || !ue_cap)
		return -1;

	/* FIXME: Send UERegisterAccept */
}

static int hnbgw_rx_initiating_msg(struct hnb_context *hnb, struct InitiatingMessage *imsg)
{
	int rc;

	switch (imsg->procedureCode) {
	case HNBAP_PC_HNBRegister:	/* 8.2 */
		if (imsg->value.type != asn1_type_HNBRegisterRequest)
			return -1;
		rc = hnbgw_rx_hnb_register_req(hnb, imsg->value.u.data);
		break;
	case HNBAP_PC_HNBDe_Register:	/* 8.3 */
		break;
	case HNBAP_PC_UERegister: 	/* 8.4 */
		if (imsg->value.type != asn1_type_UERegisterRequest)
			return -1;
		rc = hnbgw_rx_ue_register_req(hnb, imsg->value.u.data);
		break;
	case HNBAP_PC_UEDe_Register:	/* 8.5 */
		break;
	case HNBAP_PC_ErrorIndication:	/* 8.6 */
	case HNBAP_PC_TNLUpdate:	/* 8.9 */
	case HNBAP_PC_HNBConfigTransfer:	/* 8.10 */
	case HNBAP_PC_RelocationComplete:	/* 8.11 */
	case HNBAP_PC_U_RNTIQuery:	/* 8.12 */
	case HNBAP_PC_privateMessage:
		break;
	default:
		break;
	}
}

static int hnbgw_rx_successful_outcome_msg(struct hnb_context *hnb, struct SuccessfulOutcome *msg)
{

}

static int hnbgw_rx_unsuccessful_outcome_msg(struct hnb_context *hnb, struct UnsuccessfulOutcome *msg)
{

}


static int _hnbgw_hnbap_rx(struct hnb_context *hnb, struct HNBAP_PDU *pdu)
{
	int rc;

	/* it's a bit odd that we can't dispatch on procedure code, but
	 * that's not possible */
	switch (pdu->choice) {
	case HNBAP_PDU_initiatingMessage:
		rc = hnbgw_rx_initiating_msg(hnb, &pdu->u.initiatingMessage);
		break;
	case HNBAP_PDU_successfulOutcome:
		rc = hnbgw_rx_successful_outcome_msg(hnb, &pdu->u.successfulOutcome);
		break;
	case HNBAP_PDU_unsuccessfulOutcome:
		rc = hnbgw_rx_unsuccessful_outcome_msg(hnb, &pdu->u.unsuccessfulOutcome);
		break;
	default:
		return -1;
	}
}

int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg)
{
	HNBAP_PDU *pdu;
	ASN1Error err;
	int rc;

	/* decode and handle to _hnbgw_hnbap_rx() */

	rc = asn1_aper_decode(&pdu, asn1_type_HNBAP_PDU, msg->data, msgb_length(msg), &err);
	if (rc < 0) {
		LOGP(DMAIN, LOGL_ERROR, "Error in ASN.1 decode (bit=%d): %s\n", err.bit_pos, err.msg);
		return rc;
	}

	rc = _hnbgw_hnbap_rx(hnb, pdu);
	asn1_free_value(asn1_type_HNBAP_PDU, pdu);

	return rc;
}


int hnbgw_hnbap_init(void)
{

}