Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 1 | #include <osmocom/core/msgb.h> |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 2 | #include <osmocom/core/utils.h> |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 3 | |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 4 | #include <unistd.h> |
Harald Welte | ee77cff | 2015-08-30 16:57:53 +0200 | [diff] [blame] | 5 | #include <errno.h> |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 6 | #include <string.h> |
| 7 | |
Harald Welte | 30afef3 | 2015-08-30 12:28:29 +0200 | [diff] [blame] | 8 | #include "asn1helpers.h" |
| 9 | |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 10 | #include "hnbap.h" |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 11 | #include "hnbgw.h" |
| 12 | #include "hnbap_const.h" |
| 13 | |
Harald Welte | ee77cff | 2015-08-30 16:57:53 +0200 | [diff] [blame] | 14 | #define IU_MSG_NUM_IES 32 |
| 15 | #define IU_MSG_NUM_EXT_IES 32 |
| 16 | |
| 17 | /* common structure of a HNBAP / RUA / RANAP message, must have identical |
| 18 | * memory footprint as the other messages, such as HNBRegisterRequest */ |
| 19 | struct iu_common_msg { |
| 20 | ProtocolIE_Container_1 protocolIEs; |
| 21 | BOOL protocolExtensions_option; |
| 22 | ProtocolIE_Container_1 protocolExtensions; |
| 23 | }; |
| 24 | |
| 25 | /* Add an IE to a Iu message |
| 26 | * \param _msg Message to which we want to add |
| 27 | * \param[in] ie Information Element to be added (ffasn1c generated struct) |
| 28 | * \param[in] iei Information Element Identifier |
| 29 | * \param[in] type asn1_type of the IE |
| 30 | * \param[in] ext should this be an extension field? |
| 31 | */ |
| 32 | int iu_msg_add_ie(void *_msg, void *ie, int iei, ASN1CType *type, int ext) |
| 33 | { |
| 34 | struct iu_common_msg *msg = _msg; |
| 35 | ProtocolIE_Field_1 *field; |
| 36 | |
| 37 | if (ext) { |
| 38 | msg->protocolExtensions_option = TRUE; |
| 39 | if (msg->protocolExtensions.count >= IU_MSG_NUM_EXT_IES) |
| 40 | return -ERANGE; |
| 41 | field = &msg->protocolExtensions.tab[msg->protocolExtensions.count++]; |
| 42 | } else { |
| 43 | if (msg->protocolIEs.count >= IU_MSG_NUM_IES) |
| 44 | return -ERANGE; |
| 45 | field = &msg->protocolIEs.tab[msg->protocolIEs.count++]; |
| 46 | } |
| 47 | |
| 48 | field->id = iei; |
| 49 | //field->criticality = FIXME; |
| 50 | field->value.type = type; |
| 51 | field->value.u.data = ie; |
| 52 | |
| 53 | return 0; |
| 54 | } |
| 55 | |
| 56 | |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 57 | |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 58 | static int hnbgw_hnbap_tx(struct HNBAP_PDU *pdu) |
| 59 | { |
| 60 | /* FIXME */ |
| 61 | } |
| 62 | |
| 63 | static int hnbgw_tx_hnb_register_acc() |
| 64 | { |
| 65 | /* FIXME */ |
| 66 | /* Single required response IE: RNC-ID */ |
| 67 | } |
| 68 | |
| 69 | static int hnbgw_tx_ue_register_acc() |
| 70 | { |
Harald Welte | ee77cff | 2015-08-30 16:57:53 +0200 | [diff] [blame] | 71 | #if 0 |
| 72 | HNBAP_PDU pdu; |
| 73 | HNBRegisterAccept hnb_reg_acc; |
| 74 | |
| 75 | hnb_reg_acc.protocol_IEs |
| 76 | |
| 77 | pdu.choice = HNBAP_PDU_successfulOutcome; |
| 78 | pdu.u.successfulOutcome.procedureCode = HNBAP_PC_HNBRegister; |
| 79 | pdu.u.successfulOutcome.criticality = ; |
| 80 | pdu.u.successfulOutcome.value.type = asn1_type_HNBRegisterAccept; |
| 81 | pdu.u.successfulOutcome.value.u.data = &hnb_reg_acc; |
| 82 | #endif |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 83 | /* FIXME */ |
| 84 | /* Single required response IE: RNC-ID */ |
| 85 | } |
| 86 | |
Harald Welte | ee77cff | 2015-08-30 16:57:53 +0200 | [diff] [blame] | 87 | /* we type-cast to ProtocolIE_Container_1, as all the containers structs have |
| 88 | * the same definiition. This is of course ugly, but I see no cleaner way. |
| 89 | * Similarly, from the IEI it is clear what the type should be, but in a |
| 90 | * statically typed language we can only return 'void *' and hope the caller |
| 91 | * doesn the right typecast. */ |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 92 | #define FIND_IE(cont, id) find_ie((const struct ProtocolIE_Container_1 *)cont, id) |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 93 | static void *find_ie(const struct ProtocolIE_Container_1 *cont, ProtocolIE_ID id) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 94 | { |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 95 | int i; |
| 96 | |
Harald Welte | ee77cff | 2015-08-30 16:57:53 +0200 | [diff] [blame] | 97 | /* iterate over the array of IEs in the IE container and look for the first |
| 98 | * occurrence of the right IEI */ |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 99 | for (i = 0; i < cont->count; i++) { |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 100 | ProtocolIE_Field_1 *field = &cont->tab[i]; |
| 101 | if (field->id == id) { |
| 102 | OSMO_ASSERT(field->value.type); |
| 103 | /* FIXME: we shoudl check if it is the correct type, not just any type */ |
| 104 | return field->value.u.data; |
| 105 | } |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 106 | } |
| 107 | return NULL; |
| 108 | } |
| 109 | |
Harald Welte | a2e6a7a | 2015-08-29 21:47:39 +0200 | [diff] [blame] | 110 | static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, struct HNBRegisterRequest *req) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 111 | { |
| 112 | HNB_Identity *identity = |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 113 | FIND_IE(&req->protocolIEs, HNBAP_IEI_HNB_Identity); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 114 | HNB_Location_Information *loc = |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 115 | FIND_IE(&req->protocolIEs, HNBAP_IEI_HNB_Location_Information); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 116 | PLMNidentity *plmn_id = |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 117 | FIND_IE(&req->protocolIEs, HNBAP_IEI_PLMNidentity); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 118 | CellIdentity *cell_id = |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 119 | FIND_IE(&req->protocolIEs, HNBAP_IEI_CellIdentity); |
| 120 | LAC *lac = FIND_IE(&req->protocolIEs, HNBAP_IEI_LAC); |
| 121 | RAC *rac = FIND_IE(&req->protocolIEs, HNBAP_IEI_RAC); |
| 122 | SAC *sac = FIND_IE(&req->protocolIEs, HNBAP_IEI_SAC); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 123 | /* Optional: CSG-ID */ |
| 124 | |
| 125 | if(!identity || !loc || !plmn_id || !cell_id || !lac || !rac || !sac) |
| 126 | return -1; |
| 127 | |
Harald Welte | a2e6a7a | 2015-08-29 21:47:39 +0200 | [diff] [blame] | 128 | /* copy all identity parameters from the message to ctx */ |
Harald Welte | 30afef3 | 2015-08-30 12:28:29 +0200 | [diff] [blame] | 129 | asn1_strncpy(ctx->identity_info, &identity->hNB_Identity_Info, |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 130 | sizeof(ctx->identity_info)); |
Harald Welte | a2e6a7a | 2015-08-29 21:47:39 +0200 | [diff] [blame] | 131 | ctx->id.lac = asn1str_to_u16(lac); |
| 132 | ctx->id.sac = asn1str_to_u16(sac); |
| 133 | ctx->id.rac = asn1str_to_u8(rac); |
| 134 | ctx->id.cid = asn1bitstr_to_u32(cell_id); |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 135 | //ctx->id.mcc FIXME |
| 136 | //ctx->id.mnc FIXME |
Harald Welte | a2e6a7a | 2015-08-29 21:47:39 +0200 | [diff] [blame] | 137 | |
Harald Welte | ee77cff | 2015-08-30 16:57:53 +0200 | [diff] [blame] | 138 | DEBUGP(DMAIN, "HNB-REGISTER-REQ from %s\n", ctx->identity_info); |
| 139 | |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 140 | /* FIXME: Send HNBRegisterAccept */ |
| 141 | } |
| 142 | |
Harald Welte | a2e6a7a | 2015-08-29 21:47:39 +0200 | [diff] [blame] | 143 | static int hnbgw_rx_ue_register_req(struct hnb_context *ctx, struct UERegisterRequest *req) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 144 | { |
| 145 | UE_Identity *id = |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 146 | FIND_IE(&req->protocolIEs, HNBAP_IEI_UE_Identity); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 147 | Registration_Cause *reg_cause = |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 148 | FIND_IE(&req->protocolIEs, HNBAP_IEI_RegistrationCause); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 149 | UE_Capabilities *ue_cap = |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 150 | FIND_IE(&req->protocolIEs, HNBAP_IEI_UE_Capabilities); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 151 | |
| 152 | if (!id || !reg_cause || !ue_cap) |
| 153 | return -1; |
| 154 | |
| 155 | /* FIXME: Send UERegisterAccept */ |
| 156 | } |
| 157 | |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 158 | static int hnbgw_rx_initiating_msg(struct hnb_context *hnb, struct InitiatingMessage *imsg) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 159 | { |
| 160 | int rc; |
| 161 | |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 162 | switch (imsg->procedureCode) { |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 163 | case HNBAP_PC_HNBRegister: /* 8.2 */ |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 164 | if (imsg->value.type != asn1_type_HNBRegisterRequest) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 165 | return -1; |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 166 | rc = hnbgw_rx_hnb_register_req(hnb, imsg->value.u.data); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 167 | break; |
| 168 | case HNBAP_PC_HNBDe_Register: /* 8.3 */ |
| 169 | break; |
| 170 | case HNBAP_PC_UERegister: /* 8.4 */ |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 171 | if (imsg->value.type != asn1_type_UERegisterRequest) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 172 | return -1; |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 173 | rc = hnbgw_rx_ue_register_req(hnb, imsg->value.u.data); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 174 | break; |
| 175 | case HNBAP_PC_UEDe_Register: /* 8.5 */ |
| 176 | break; |
| 177 | case HNBAP_PC_ErrorIndication: /* 8.6 */ |
| 178 | case HNBAP_PC_TNLUpdate: /* 8.9 */ |
| 179 | case HNBAP_PC_HNBConfigTransfer: /* 8.10 */ |
| 180 | case HNBAP_PC_RelocationComplete: /* 8.11 */ |
| 181 | case HNBAP_PC_U_RNTIQuery: /* 8.12 */ |
| 182 | case HNBAP_PC_privateMessage: |
| 183 | break; |
| 184 | default: |
| 185 | break; |
| 186 | } |
| 187 | } |
| 188 | |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 189 | static int hnbgw_rx_successful_outcome_msg(struct hnb_context *hnb, struct SuccessfulOutcome *msg) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 190 | { |
| 191 | |
| 192 | } |
| 193 | |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 194 | static int hnbgw_rx_unsuccessful_outcome_msg(struct hnb_context *hnb, struct UnsuccessfulOutcome *msg) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 195 | { |
| 196 | |
| 197 | } |
| 198 | |
| 199 | |
Harald Welte | a2e6a7a | 2015-08-29 21:47:39 +0200 | [diff] [blame] | 200 | static int _hnbgw_hnbap_rx(struct hnb_context *hnb, struct HNBAP_PDU *pdu) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 201 | { |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 202 | int rc; |
| 203 | |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 204 | /* it's a bit odd that we can't dispatch on procedure code, but |
| 205 | * that's not possible */ |
| 206 | switch (pdu->choice) { |
| 207 | case HNBAP_PDU_initiatingMessage: |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 208 | rc = hnbgw_rx_initiating_msg(hnb, &pdu->u.initiatingMessage); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 209 | break; |
| 210 | case HNBAP_PDU_successfulOutcome: |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 211 | rc = hnbgw_rx_successful_outcome_msg(hnb, &pdu->u.successfulOutcome); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 212 | break; |
| 213 | case HNBAP_PDU_unsuccessfulOutcome: |
Harald Welte | b3dae30 | 2015-08-30 12:20:09 +0200 | [diff] [blame] | 214 | rc = hnbgw_rx_unsuccessful_outcome_msg(hnb, &pdu->u.unsuccessfulOutcome); |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 215 | break; |
| 216 | default: |
| 217 | return -1; |
| 218 | } |
| 219 | } |
| 220 | |
Harald Welte | a2e6a7a | 2015-08-29 21:47:39 +0200 | [diff] [blame] | 221 | int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg) |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 222 | { |
Harald Welte | ee77cff | 2015-08-30 16:57:53 +0200 | [diff] [blame] | 223 | HNBAP_PDU *pdu; |
| 224 | ASN1Error err; |
| 225 | int rc; |
| 226 | |
| 227 | /* decode and handle to _hnbgw_hnbap_rx() */ |
| 228 | |
| 229 | rc = asn1_aper_decode(&pdu, asn1_type_HNBAP_PDU, msg->data, msgb_length(msg), &err); |
| 230 | if (rc < 0) { |
| 231 | LOGP(DMAIN, LOGL_ERROR, "Error in ASN.1 decode (bit=%d): %s\n", err.bit_pos, err.msg); |
| 232 | return rc; |
| 233 | } |
| 234 | |
| 235 | rc = _hnbgw_hnbap_rx(hnb, pdu); |
| 236 | asn1_free_value(asn1_type_HNBAP_PDU, pdu); |
| 237 | |
| 238 | return rc; |
Harald Welte | ba43de4 | 2015-08-29 20:33:16 +0200 | [diff] [blame] | 239 | } |
| 240 | |
| 241 | |
| 242 | int hnbgw_hnbap_init(void) |
| 243 | { |
| 244 | |
| 245 | } |